poj 2117
题意:一个无向图,现在要去掉其中一个点,要求去掉这个点之后,总连通分支数最大。
思路:割点,连通分量。主要分三种情况:
1、最普通的情况:如果有边,而且存在割点,就是tarjon算法的深搜过程中求出所有割点的子树的个数(其实也就是如果去掉割点,能使连通分支数增加的个数)的最大值,再加上原来的强连通分支数即可。
2、最容易出错的情况:如果没有边,则应该去掉一个点后,连通分支数为原顶点数减去1。
3、如果有边,但是图中不存在割点,则输出原来图中连通分支数就行了。
代码:
#include<iostream>
#include<fstream>
using namespace std;
int m,n;
struct e{
int data;
e *next;
};
e edge[10011];
int dfn[10011],cnt[10011],low[10011];
int index;
void tar(int s){
dfn[s]=low[s]=++index;
cnt[s]=0;
e *p=edge[s].next;
while(p){
if(dfn[p->data]==0)
{
tar(p->data);
if(low[p->data]>=dfn[s])
{
cnt[s]++;
}
low[s]=min(low[s],low[p->data]);
}
else
{
low[s]=min(low[s],dfn[p->data]);
}
p=p->next;
}
}
void solve(){
int i,j=0,k;
index=0;
memset(dfn,0,sizeof(dfn));
for(i=0;i<n;i++)
{
if(dfn[i]==0)
{
j++;
tar(i);
cnt[i]--;
}
}
k=0;
for(i=0;i<n;i++)
k=max(k,cnt[i]);
if(m==0) cout<<n-1<<endl;
else cout<<j+k<<endl;
}
void read(){
// ifstream cin("in.txt");
int i,j,k,s,t;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) return;
for(i=0;i<n;i++)
edge[i].next=0;
for(i=1;i<=m;i++)
{
// cin>>s>>t;
scanf("%d%d",&s,&t);
e *p=new e;
p->data=s;
p->next=edge[t].next;
edge[t].next=p;
e *q=new e;
q->data=t;
q->next=edge[s].next;
edge[s].next=q;
}
solve();
}
}
int main(){
read();
return 0;
}
浙公网安备 33010602011771号