SRM 441 Div1 Medium StrangeCountry
問題概要
N個の都市からなる国がある。
いくつかの都市の間には双方向に通行可能な道路が走っている。
次のような操作を何度か行うことにより任意の2つの都市を(直接または間接に)行き来できるようにしたい。
直接道路で結ばれている都市A,Bと直接道路で結ばれている都市C,Dを選ぶ。
A-Bの道路C-Dの道路を壊し、A-DとB-C間に、もしくはA-C,B-D間に新たに道路を作る。
この操作を最低何回行えば任意の2つの都市は行き来可能になるか求めよ。
不可能な場合は-1を出力せよ。
制約条件
グラフは隣接行列の形で与えられる。N≦50
方針
辺の数がN-1本がグラフが連結になる(この場合木になる)ため必要な最低の本数。
N-1本以上なら、次のように繰り返し操作を行うことで、グラフが連結になることがわかる。
二つの連結成分A,Bを取る。
Aの辺の数はAの頂点の数以上として一般性を失わない。
(要するに辺があまっている連結成分をAとする。)
するとAには必ずループがあるはずなので、ループで隣合う頂点をv1,v2とでもすれば、
Bの適当な2頂点とv1,v2について辺の組み換えを行うと、
A,B全体が連結になる。(v1,v2はループだったので別のパスでつながっているから)
ただしコーナーケースがあり、連結成分として孤立点があった場合、
辺の組み換えができないので、どうやっても全体を連結にすることができなくなる。
以上をまとめると次のように判別すればいいことがわかる。
辺の数がN-1本未満なら不可能。
孤立点があっても不可能。
そのどちらでもないときは可能。
ソースコード
int n, e[50][50]; bool v[50]; void dfs(int c){ v[c]=1; rep(i,n)if(e[c][i]&&!v[i])dfs(i); } class StrangeCountry { public: int transform(vector <string> g) { n=g.size(); int edge=0; rep(i,n)rep(j,n){ e[i][j]=g[i][j]=='Y'; if(e[i][j])edge++; } if(edge/2<n-1)return -1; rep(i,n){ bool ok=0; rep(j,n)if(e[i][j])ok=1; if(!ok)return -1; } rep(i,n)v[i]=0; int ans=-1; rep(i,n)if(!v[i]){ ans++; dfs(i); } return ans; } };