SRM 299 Div2-1000: StrangeParticles
keyword
有向グラフ 強連結成分分解 C++
問題概要
N(<50)個の粒子がある。2つの粒子が衝突したとき、どちらか片方が消滅することがある。任意の2粒子間で衝突が起こったときの結果が与えられる。好きな順に衝突を起こせるとき、最終的に粒子を何個まで減らせるか求める問題。
解法
xとyが衝突したときxが消滅するならxからyへ辺を張る。このようなグラフを強連結成分分解してDAGに落とす。sinkの個数が答えとなる。
int pars[100]; int getRoot(int x){ return x==pars[x]?x:(pars[x]=getRoot(pars[x])); } int merge(int x, int y){ return pars[getRoot(x)] = getRoot(y); } class StrangeParticles { public: int remain(vector <string> g) { for(int i=0; i<100; i++){ pars[i] = i; } int N = g.size(); for(int i=0; i<N; i++)for(int j=0; j<N; j++){ if(g[i][j] == '+') g[i][j] = '-'; else if(g[i][j] == '-') g[i][j] = '+'; } for(int i=0; i<N; i++){ for(int j=0; j<N; j++){ if(g[i][j] == '+') g[i][j] = '0'; } } for(int k=0; k<N; k++){ for(int i=0; i<N; i++){ for(int j=0; j<N; j++)if(g[i][k]=='-' && g[k][j]=='-'){ g[i][j] = '-'; } } } for(int i=0; i<N; i++){ for(int j=i+1; j<N; j++)if(g[i][i] == '-' && g[j][j] == '-' && g[i]==g[j]){ merge(i,j); } } for(int i=0; i<N; i++)for(int j=0; j<N; j++)if(j!=pars[j]){ g[i][j] = '0'; } for(int i=0; i<N; i++)g[i][i] = '0'; int ret = 0; for(int i=0; i<N; i++)if(i==pars[i]){ if(g[i] == string(N,'0')) ret++; } return ret; }