1161 Walls
問題概要
壁によってM個の領域に仕切られた国がある。
国内にはN個の町があり、町の中心と町の中心をつなぐように壁は立てられている。
町のうちL個にクラブの会員が一人ずついて、クラブの集会を開く。
会員は領域から領域へ移動するとき壁を越えなければならない。各会員が壁を越える回数の合計を最小にするような領域を求め、そのときの壁を越える回数の合計を出力せよ。
M≦200,N≦250,L≦30を満たす。
解法
どこが町なのか問題文から読み取りにくいが、グラフの頂点が町。
頂点からは最初どの領域へもコスト0で移動できることに注意。
考えるのは双対なグラフ。
最初のグラフをF,Fの双対なグラフをGとすれば、Gは、グラフFの各領域を頂点として、Fのグラフで隣り合う領域同士を辺で結んだグラフ。
双対なグラフGは、以下のように作ればよい。
- Fの二つの領域A,Bが同じ辺を共有するならそれは隣接しているので、Gの頂点A,Bを辺で結ぶ。
双対グラフ上でワーシャルフロイドをすれば各領域間の最短距離(壁を越える数)が求められる。
全ての領域について、会員の移動距離の合計を求めて、それが最小となるような場所を探せばよい。
壁は微妙に数が多いので二分探索(下のコードではSTLのsetを使用)する必要があるかも。
ソースコード
set<pi> S[250]; set<int> T[250]; int m,n,l,p[30],e[200][200]; int main() { scanf("%d%d%d",&m,&n,&l); rep(i,l)scanf("%d",p+i); rep(i,m) { int a,b[250],c,d; scanf("%d",&a); rep(j,a)scanf("%d",b+j),T[b[j]].insert(i); rep(j,a) { c=b[j]; d=b[(j+1)%a]; if(c>d)swap(c,d); S[i].insert(mp(c,d)); } } rep(j,m)rep(i,j) { e[i][j]=e[j][i]=inf; fr(it,S[i])if(S[j].count(*it)) { e[i][j]=e[j][i]=1; break; } } rep(k,m)rep(i,m)rep(j,m)e[i][j]=min(e[i][j],e[i][k]+e[k][j]); int ans=inf; rep(i,m) { int sum=0; rep(j,l) { int mn=inf; fr(k,T[p[j]])mn=min(mn,e[i][*k]); sum+=mn; } ans=min(ans,sum); } printf("%d\n",ans); return 0; }