题意
给定一个无向图并规定,当删除图中的某个顶点时,将会同时把与之连接的边一起删除。接下来给出k个查询,每个查询给出一个欲删除的顶点编号,求删除该顶点(和与其连接的边)后需要增加多少条边,才能使图变为连通(注: k次查询均在原图上进行)。
思路
注意是无向图
上来直接写了个暴力的代码,改了无向图的bug后交一发直接AC了???
暴力思路挺简单的,分别删除(1~n)号点后剩余的连通块数,不必真的删除,每次访问删除点时跳过就好了,然后每次的答案就是连通块数减一。
不过数据范围确实小,求连通块的复杂度是:(mathcal O(n+m)),这样总的复杂度就是(mathcal O(qm)),(color{green}{AcWing})上给的范围是(3500000)。
const int N=1010;
vector<int> g[N];
bool vis[N];
int n,m,q;
void dfs(int u,int x)
{
vis[u]=true;
for(int i=0;i<g[u].size();i++)
{
int j=g[u][i];
if(j == x || vis[j]) continue;
dfs(j,x);
}
}
int main()
{
cin>>n>>m>>q;
while(m--)
{
int a,b;
cin>>a>>b;
g[a].pb(b);
g[b].pb(a);
}
while(q--)
{
memset(vis,0,sizeof vis);
int x;
cin>>x;
int cnt=0;
for(int i=1;i<=n;i++)
if(!vis[i] && i != x)
{
dfs(i,x);
cnt++;
}
cout<<cnt-1<<endl;
}
//system("pause");
return 0;
}
当然,既然是求连通块,那怎么能少的了并查集捏。只要不合并删除点和领接点就行了。
const int N=1010;
struct Edge{
int a,b;
}e[N*N];
int p[N];
int n,m,q;
int find(int x)
{
if(x != p[x]) p[x]=find(p[x]);
return p[x];
}
int main()
{
cin>>n>>m>>q;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
e[i]={a,b};
}
while(q--)
{
for(int i=1;i<=n;i++) p[i]=i;
int x;
cin>>x;
int cnt=0;
for(int i=0;i<m;i++)
{
int a=e[i].a,b=e[i].b;
if(a != x && b != x)
{
int pa=find(a),pb=find(b);
p[pa]=pb;
}
}
for(int i=1;i<=n;i++)
if(p[i] == i && i != x)
cnt++;
cout<<cnt-1<<endl;
}
//system("pause");
return 0;
}