BWInf 2011, câu hỏi 5: Thị trấn sinh đôi


8

Đây là một thách thức ban đầu là một thử thách cho Bundeswettbewerb Informatik (cuộc thi liên bang về khoa học máy tính [?]), Một cuộc thi dành cho học sinh trung học. Trái ngược với câu hỏi ban đầu, nơi bạn phải tìm một giải pháp tốt và viết một số tài liệu, tôi muốn bạn chơi golf này. Tôi cố gắng tái tạo câu hỏi tốt nhất có thể:

Thử thách

Nhiều thị trấn ở châu Âu có cái gọi là thị trấn sinh đôi . Năm nay, có một Năm Thánh đặc biệt nơi mỗi cặp thị trấn sinh đôi ở EU tổ chức một lễ hội để kỷ niệm mối quan hệ đối tác của họ. Để đảm bảo rằng không có thành phố nào phải tổ chức quá nhiều lễ hội, mỗi thành phố có một giới hạn của lễ hội mà nó có thể tổ chức. Có thể phân phối các lễ hội giữa các thị trấn sinh đôi theo cách, sao cho mỗi cặp thị trấn sinh đôi tổ chức một lễ hội ở một trong hai thị trấn và không có thị trấn nào tổ chức nhiều lễ hội hơn mức cho phép? Nếu có, giải thích làm thế nào.

Đây là bản đồ của một số thị trấn, quan hệ đối tác của họ và giới hạn của các lễ hội.

quan hệ đối tác http://dl.dropbox.com/u/1869832/partnerships.png

Yêu cầu

  • Chương trình của bạn phải chấm dứt sự cố trong một phút cho cả hai thử nghiệm. (Xem bên dưới)
  • Tham khảo các mẫu thử cho định dạng đầu vào.
  • Đầu ra phải trống nếu không có giải pháp nào tồn tại và phải có định dạng sau: Một dòng cho mỗi cặp thị trấn sinh đôi, anếu city1tổ chức lễ hội, bnếu không.

    <city1>, <city2>, <a/b>
    
  • Giải pháp có số lượng ký tự ít nhất thỏa mãn yêu cầu sẽ thắng. Trong trường hợp hòa, chương trình được gửi đầu tiên sẽ thắng.

  • Quy tắc golf thông thường áp dụng.

Tủ thử

Nhiệm vụ ban đầu có hai testcase. Tôi đã tải chúng lên github .


Gợi ý: có một mức giảm đơn giản cho luồng cực đại số nguyên.
Peter Taylor

@Peter những gì về khớp bipartite?
FUZxxl

Việc giảm này là một phần mở rộng của việc giảm kết hợp bipartite tiêu chuẩn và sẽ hiệu quả hơn so với việc giảm thông qua kết hợp lưỡng cực (sẽ yêu cầu biến mỗi thành phố thành ncác nút, trong đó ngiới hạn ngân sách của thành phố).
Peter Taylor

Câu trả lời:


2

Python, 380 ký tự

import sys
N={};H={};X={}
for L in open(sys.argv[1]):n,x,y=L.split('"');N[x]=int(n);H[x]=0;X[x]=[]
for L in open(sys.argv[2]):s,t=eval(L);X[s]+=[t]
p=1
while p:
 p=0
 for x in N:
  if len(X[x])>N[x]:
   p=1;S=[y for y in X[x]if H[y]<H[x]]
   if S:X[x].remove(S[0]);X[S[0]]+=[x]
   else:H[x]+=1
   if H[x]>2*len(N):sys.exit(0)
for x in N:
 for y in X[x]:print'"%s", "%s", a'%(x,y)

Mã này sử dụng thuật toán dòng chảy tối đa theo kiểu đẩy lại . N[x]là số lượng các bên được phép tại x, X[x]là danh sách các thành phố đối tác hiện được lên kế hoạch lưu trữ tại x(có thể dài hơn N[x]trong thuật toán) và H[x]là chiều cao được gắn nhãn của x. Đối với bất kỳ thành phố nào được đăng ký vượt mức, chúng tôi sẽ đẩy một trong các bên dự kiến ​​của mình đến một thành phố đối tác thấp hơn hoặc tăng chiều cao của nó.


2

C #, 1016 992 916 ký tự

Mất 4 giây cho tôi trên bộ thử nghiệm lớn; hiệu suất có thể dễ dàng được cải thiện rất nhiều bằng cách làm cho Xmột HashSet<s>chứ không phải là một List<s>.

using System;using System.Collections.Generic;using System.IO;using System.Linq;using
s=System.String;class D<T>:Dictionary<s,T>{}class E:D<int>{static void Main(s[]x){s
S="",T=">",l;s[]b;D<E>R=new D<E>(),P=new D<E>();R[S]=new E();R[T]=new E();foreach(s L in
File.ReadAllLines(x[0])){b=L.Split('"');s f=b[1];R[T][f]=0;R[f]=new E();P[f]=new
E();R[f][T]=int.Parse(b[0].Trim());}foreach(s L in File.ReadAllLines(x[1])){b=L.Split('"');s
f=b[1],t=b[3],v=f+t;R[v]=new
E();R[v][S]=R[f][v]=R[t][v]=0;P[f][t]=R[S][v]=R[v][f]=R[v][t]=1;}for(;;){List<s>X=new
s[]{S}.ToList(),A=X.ToList();w:while((l=A.Last())!=T){foreach(s t in
R[l].Keys){if(!X.Contains(t)&R[l][t]>0){X.Add(t);A.Add(t);goto
w;}}A.RemoveAt(A.Count-1);if(!A.Any())goto q;}l=S;foreach(s n in
A.Skip(1)){R[l][n]--;R[n][l]++;l=n;}}q:if(R[S].Values.Contains(1))return;foreach(s
f in P.Keys)foreach(s t in P[f].Keys)Console.WriteLine(f+", "+t+", "+"ba"[R[f][f+t]]);}}

Điều này sử dụng việc giảm lưu lượng tối đa mà tôi đã gợi ý trước đó trong các bình luận. Các đỉnh là

  1. Một nguồn mới được tạo ra Svà chìm T.
  2. Các quan hệ đối tác.
  3. Những thành phố.

Các cạnh là

  1. Từ nguồn đến từng quan hệ đối tác với lưu lượng 1.
  2. Từ mỗi quan hệ đối tác đến từng thành phố trong quan hệ đối tác với lưu lượng 1.
  3. Từ mỗi thành phố đến bồn rửa với lưu lượng bằng với ngân sách của thành phố đó.

Thuật toán là Ford-Fulkerson với DFS. Rõ ràng là một tiên nghiệm rằng mỗi đường tăng sẽ tăng lưu lượng lên 1, do đó, tối ưu hóa việc loại bỏ tính toán của dòng chảy của đường dẫn không ảnh hưởng tiêu cực đến hiệu suất.

Có những cách tối ưu hóa khác có thể bằng cách đưa ra các giả định như "Tên của các tệp đầu vào sẽ không bao giờ giống với tên của các thành phố", nhưng đó là một chút IMO iffy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.