http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2506
连通分量 缩点后形成新的图(不用新建也可以) 是一个森林
如果缩点后是就剩一个点 则答案为 0
否则 对于缩点后的某一个点 如果和它相连点(缩点后的)有大于等于2个 则无需再连
如果和它相连的有一个点 则需要加一个边连接它 如果没有点和它相连 则需要加两条
统计总共需要加的边的个数sum 因为每条边连接两个点 所以答案为 (sum+1)/2
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<algorithm>
#define LL long long
using namespace std;
const int N=5015;
const int M=10005;
int head[N],I;
struct node
{
int j,next;
}side[M*2];
int dfn[N],low[N],f[N],deep;
bool visited[N],in[N];
stack<int>st;
set<int>numt[N];
void add(int i,int j)
{
side[I].j=j;
side[I].next=head[i];
head[i]=I++;
}
void dfs(int x,int pre)
{
dfn[x]=low[x]=deep++;
st.push(x);
in[x]=true;
visited[x]=true;
for(int t=head[x];t!=-1;t=side[t].next)
{
int j=side[t].j;
if(j==pre)
continue;
if(!visited[j])
{
dfs(j,x);
low[x]=min(low[x],low[j]);
}else if(in[j])
{
low[x]=min(low[x],dfn[j]);
}
}
if(low[x]==dfn[x])
{
while(st.top()!=x)
{
in[st.top()]=false;
f[st.top()]=x;
st.pop();
}
in[st.top()]=false;
f[st.top()]=x;
st.pop();
}
}
int main()
{
//freopen("data.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(head,-1,sizeof(head));
I=0;
int n,m;
scanf("%d %d",&n,&m);
while(m--)
{
int l,r;
scanf("%d %d",&l,&r);
add(l,r);
add(r,l);
}
while(!st.empty())
st.pop();
memset(in,false,sizeof(in));
memset(visited ,false,sizeof(visited));
deep=1;
int treenum=0;
for(int i=1;i<=n;++i)
{
if(!visited[i])
{
dfs(i,-1);
++treenum;
}
}
for(int i=1;i<=n;++i)
numt[i].clear();
for(int i=1;i<=n;++i)
{
for(int t=head[i];t!=-1;t=side[t].next)
{
int j=side[t].j;
if(f[i]!=f[j])
{
numt[f[i]].insert(f[j]);
}
}
}
int leftnum=0;
int sum=0;
for(int i=1;i<=n;++i)
{
if(f[i]==i)
{
if(numt[i].size()==0)
{sum+=2;leftnum++;}
if(numt[i].size()==1)
{sum+=1;leftnum++;}
}
}
if(treenum==1&&leftnum==1)
{
printf("0\n");
}else
{
printf("%d\n",(sum+1)/2);
}
}
return 0;
}
浙公网安备 33010602011771号