http://poj.org/problem?id=2117
题目大意,就是问删除某个点,然后求出最多的联通块数目
由于第一次写割点所以根本不会,看着别人代码理解了好久。最后发现,3 0这种情况应该输出2的,必须要删点。就因为这个WA了好多发。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N = 1e4 + 5;
vector <int> G[N];
int p, c, low[N], dfn[N];
bool is_cut[N];
int par[N], add_block[N];
int ind = 0;
void Tarjan(int u, int Father)
{
par[u] = Father;
dfn[u] = low[u] = ind++;
int son = 0;
for(int j = 0; j < G[u].size(); ++j)
{
int v = G[u][j];
if(v == Father) //只能向下遍历
continue;
if(dfn[v] == -1)
{
son++; //若u为割点,可以分出的联通块数目,该项只对树根有效
Tarjan(v, u);
low[u] = min(low[u], low[v]);
if(u != Father && low[v] >= dfn[u]) //当u不是树根时,如果存在low >= dfn这种情况
{
is_cut[u] = 1; //说明u是一个割点,并且记录下其分割出来的联通块的数目
add_block[u]++;
}
}
else
low[u] = min(low[u], dfn[v]);
}
if(u == Father && son > 1) //如果u等于father,则说明它是树根。此时若其次数大于2则
is_cut[u] = 1; //该树根为割点
if(u == Father) //若它为树根,则记录下他的联通块数目,用不用得上再说
add_block[u] = son - 1;
}
void Count()
{
int cnt = 0;
for(int i = 0; i < p; i++)
{
if(dfn[i] == -1)
{
Tarjan(i, i);
cnt++;
}
}
int Max = 0;
for(int i = 0; i < p; ++i)
Max = max(Max, add_block[i] + cnt);
printf("%d\n", Max);
}
int main()
{
while(scanf("%d%d", &p, &c) != EOF)
{
if(p == 0 && c == 0)
break;
memset(dfn, -1, sizeof(dfn));
memset(low, -1, sizeof(low));
memset(is_cut, false, sizeof(is_cut));
memset(add_block, 0, sizeof(add_block));
ind = 0;
for(int i = 0; i < N; i++)
G[i].clear();
for(int i = 1; i <= c; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);/*邻接表储存无向边*/
G[v].push_back(u);
}
Count();
}
return 0;
}