BWInf 2011, pergunta 5: Cidades gêmeas

8

Esse é um desafio que originalmente era uma tarefa do alemão Bundeswettbewerb Informatik (concurso federal de ciência da computação [?]), Um concurso para estudantes do ensino médio. Ao contrário da pergunta original, onde você precisa encontrar uma boa solução e escrever alguma documentação, eu quero que você jogue isso. Eu tento replicar a pergunta da melhor maneira possível:

Desafio

Muitas cidades da Europa têm as chamadas cidades gêmeas . Este ano, há um Jubileu especial em que cada par de cidades gêmeas na UE organiza um festival para celebrar sua parceria. Para garantir que nenhuma cidade precise organizar muitos festivais, cada cidade tem um limite de festivais que pode organizar. É possível distribuir os festivais entre as cidades gêmeas de uma maneira que cada par de cidades gêmeas organize um festival em uma das duas cidades e nenhuma cidade organize mais festivais do que é permitido? Se sim, explique como.

Este é um mapa de algumas cidades, suas parcerias e seus limites de festivais.

parcerias http://dl.dropbox.com/u/1869832/partnerships.png

Exigências

  • Seu programa deve encerrar o problema em um minuto cada para os dois casos de teste. (Ver abaixo)
  • Consulte as caixas de teste para o formato de entrada.
  • A saída deve estar vazia se não houver solução e deve ter o seguinte formato: Caso contrário, uma linha para cada par de cidades gêmeas, ase city1organizar o festival b.

    <city1>, <city2>, <a/b>
    
  • A solução com o menor número de caracteres que satisfaz os requisitos vence. Em caso de empate, o programa enviado primeiro vence.

  • Aplicam-se regras usuais de código-golfe.

Casos de teste

A tarefa original tinha dois casos de teste. Eu os carreguei no github .

FUZxxl
fonte
Dica: há uma redução simples para o fluxo máximo inteiro.
Peter Taylor
@ Peter e a correspondência bipartida?
FUZxxl
A redução é uma pequena extensão da redução de correspondência bipartida padrão e deve ser mais eficiente do que uma redução via correspondência bipartida (o que exigiria transformar cada cidade em nnós, onde né o limite de orçamento da cidade).
Peter Taylor

Respostas:

2

Python, 380 caracteres

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)

Esse código usa um algoritmo de fluxo máximo no estilo push-re-label . N[x]é o número de participantes permitido em x, X[x]é a lista de cidades parceiras atualmente programadas para hospedar em x(que pode ser maior que N[x]durante o algoritmo) e H[x]é a altura rotulada de x. Para qualquer cidade com excesso de assinaturas, enviamos uma das partes programadas para uma cidade parceira mais baixa ou aumentamos sua altura.

Keith Randall
fonte
2

C #, 1016992916 caracteres

Leva 4 segundos para mim no grande conjunto de testes; o desempenho pode ser facilmente aprimorado muito fazendo Xum HashSet<s>ao invés de um 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]]);}}

Isso usa a redução ao fluxo máximo, como sugeri anteriormente nos comentários. Os vértices são

  1. Uma fonte Se coletor recém-gerados T.
  2. As parcerias.
  3. As cidades.

As arestas são

  1. Da fonte a cada parceria com capacidade de fluxo 1.
  2. De cada parceria para cada cidade na parceria com capacidade de fluxo 1.
  3. De cada cidade para a pia com capacidade de fluxo igual ao orçamento da cidade.

O algoritmo é Ford-Fulkerson com DFS. É óbvio a priori que cada caminho aumentado aumentará o fluxo em 1; portanto, a otimização do golfe de remover o cálculo do fluxo do caminho não tem efeito negativo no desempenho.

Existem outras otimizações possíveis, fazendo suposições como "Os nomes dos arquivos de entrada nunca serão os mesmos das cidades", mas isso é um pouco confuso para IMO.

Peter Taylor
fonte