解题思路:我的第一份代码用并查集加逆边做的,就是先假定已经把要炸的城市都给炸了,然后不断往并查集中加入被炸掉的点。如果并查集的分块数减小超过1个,就代表去掉这条边会影响联通性。第二份是每炸掉一个城市就用dfs看一下连通分量的情况,比第一种费时。
并查集:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
int map[501][501],fg[502],id[502],p[501],fa[501];
using namespace std;
int find(int a)
{
if(fa[a]!=a)
fa[a]=find(fa[a]);
return fa[a];
}
void unite(int a,int b)
{
int x=find(a),y=find(b);
fa[x]=fa[y];
}
int main()
{
freopen("t.txt","r",stdin);
int n,m,k,u,v;
scanf("%d%d",&n,&m);
memset(map,0,sizeof(map));
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=1;
}
scanf("%d",&k);
memset(fg,0,sizeof(fg));
memset(p,0,sizeof(p));
for(int i=0;i<n;i++) fa[i]=i;
for(int i=0;i<k;i++)
{
scanf("%d",&id[i]);
p[id[i]]=1;
}
for(int i=0;i<n;i++)
{
if(!p[i])
{
for(int j=0;j<n;j++)
{
if(!p[j]&&map[j][i])
{
if(find(i)!=find(j))
unite(i,j);
}
}
}
}
for(int i=k-1;i>=0;i--)
{
int v=id[i],cnt=0;
p[v]=0;
for(int j=0;j<n;j++)
{
if(!p[j]&&map[v][j])
{
if(find(v)!=find(j))
{
cnt++;
unite(v,j);
}
}
}
if(cnt>1) fg[v]=1;
}
for(int i=0;i<k;i++)
{
if(fg[id[i]])
printf("Red Alert: City %d is lost!\n",id[i]);
else
printf("City %d is lost.\n",id[i]);
}
if(k==n)
printf("Game Over.\n");
return 0;
}
dfs:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int map[502][502],vis[502],n,m,fg[502];
int cnt,pre;
void dfs(int u)
{
vis[u]=1;
for(int i=0;i<n;i++)
{
if(!fg[i]&&!vis[i]&&map[u][i])
{
dfs(i);
}
}
}
int count()
{
int c=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
if(!fg[i]&&!vis[i])
{
dfs(i);
c++;
}
}
return c;
}
int main()
{
//freopen("t.txt","r",stdin);
int k,u,v,id,r;
scanf("%d%d",&n,&m);
memset(map,0,sizeof(map));
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=1;
}
scanf("%d",&k);
cnt=0,pre=count(),r=k;
memset(fg,0,sizeof(fg));
while(k--)
{
scanf("%d",&id);
fg[id]=1;
cnt=count();
if(cnt-pre>0) printf("Red Alert: City %d is lost!\n",id);
else printf("City %d is lost.\n",id);
pre=cnt;
}
if(r==n) printf("Game Over.\n");
return 0;
}