题目大意:有n个核电站,去掉一个核电站,最多能把剩下的分成几块。
解题思路:求出每个子图的割顶和能判断出这个割顶的儿子数,算出每个割顶能把子块分成几块。最后加上本来图的块数。
先是终止条件写错了,一直OLE,样例居然能过。。。然后就是求割顶能把图分成多少块的地方少加了1,最后在输出的时候加上应该也一样。。
但是有个地方没搞懂的,假设一个子图被一个割顶分成了k+1份,那么能确定这个点是割顶的儿子数就是k(SPFnumber里面存的值),一个图本身有t块,那么去掉这个割顶能产生的块数应该等于k+1+t-1=k+t块,为什么结果是k+t+1呢。。。。难道SPFNumber里面存的就是一坨翔?(一堆废话,我的心情很复杂。。。)
最后发现原来SPFNumber里面的数据,每处理一组数据的时候初值为-1,最后结果不少一才怪。。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int low[11000],dep[11000];
int SPFNumber[11000];//求割顶被求次数,用来求去掉割顶后分成多少联通块
int boo[11000];//染色标记
int deep;//给图上所有点按照遍历顺序标号,每个点的标号不重记
int bridge;//求桥的数量
int tip;
int n,m;
//邻接表
int now[11000],test=0;
int tail;
class PPP
{
public:
int point;
int next;
}way[100000];
void clearlist()
{
tail = 0;
memset(now,0,sizeof(now));
memset(SPFNumber,0,sizeof(SPFNumber));
memset(boo,0,sizeof(boo));
}
void insert(int a,int b)
{
tail++;
way[tail].point = b;
way[tail].next = now[a];
now[a] = tail;
}
//基于深搜的标记法求割顶与桥
void dfs(int k,int father)
{
int son;
boo[k] = 1;
dep[k] = ++deep;
low[k] = dep[k];
for (int i = now[k] ; i != 0 ; i = way[i].next)
{
son = way[i].point;
if (son == father) continue;
if (boo[son]) {
low[k] = low[k]<dep[son]?low[k]:dep[son];
continue;
}
dfs(son,k);
low[k] = low[k]<low[son]?low[k]:low[son];
if (low[son] >= dep[k]) SPFNumber[k] ++;
if (low[i] > dep[k]) bridge ++;
}
}
int main()
{
//freopen("a.txt","r",stdin);
//freopen("my.txt","w",stdout);
int x,y,ans,sum;
while (1)
{
deep = 0;
clearlist();
scanf("%d%d",&n,&m);
if (n == 0 && m == 0) break;
for (int i = 1 ; i <= m ; i ++)
{
scanf("%d%d",&x,&y);
insert(x,y);
insert(y,x);
}
bridge = 0;
sum = 0;
ans = -99999;
for (int i = 0 ; i < n ; i ++)
{
if (boo[i] == 1) continue;
dfs(i,-1);
SPFNumber[i] --;
sum++;
}
for (int i = 0 ; i < n ; i ++)
ans = ans>SPFNumber[i]?ans:SPFNumber[i];
printf("%d\n",ans+sum);
}
return 0;
}