http://acm.hust.edu.cn/vjudge/contest/130396#problem/C
题意:一个图,给一个源点可以流水,只要在一个连通块都能流到。找一个点,使得去掉这个点后,水能流到的点最少。
割点的应用,找出所有的割点,枚举删除每个割点后有多少个点不能被流到。
因为数据范围只有100,所以标记割点过后,从源点开始dfs,能跑多少点就跑多少点,剩下的就是不能跑到的了,对枚举的每个割点取max就行了。
CODE
#include <bits/stdc++.h>
using namespace std;
const int N = 100+10;
struct node{
int en,next;
}E[N*N];
int n,m,s;
int top,dfs_clock;
int head[N];
int cut[N]; ///标记割点
int low[N],dfn[N]; ///Tarjan用
bool vis[N]; ///标记割点后的dfs用
void Init() ///初始化
{
dfs_clock = 1;
top = 0;
for(int i = 0;i < N;i++){
head[i] = -1;
low[i] = dfn[i] = cut[i] = 0;
}
}
void add(int u,int v)
{
E[top].en = v;
E[top].next = head[u];
head[u] = top++;
}
void Tarjan(int u)
{
dfn[u] = low[u] = dfs_clock++;
for(int i = head[u];i != -1;i= E[i].next){
int v = E[i].en;
if(!dfn[v]){
Tarjan(v);
low[u] = min(low[u],low[v]);
if(low[v] >= dfn[u]) cut[u] = 1;
}
else
low[u] = min(low[u],dfn[v]);
}
}
void dfs(int u)
{
vis[u] = 1;
for(int i = head[u];i != -1;i = E[i].next){
int v = E[i].en;
if(vis[v]) continue;
dfs(v);
}
}
int main(void)
{
while(scanf("%d",&n) != EOF && n){
Init();
scanf("%d%d",&s,&m);
for(int i = 1;i <= m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
int pos;
int maxx = -1;
Tarjan(s);
for(int i = 1;i <= n;i++){
if(cut[i]){
memset(vis,false,sizeof vis);
vis[i] = 1;
dfs(s);
int cnt = 0;
for(int i = 1;i <= n;i++){
if(!vis[i]) cnt++;
}
if(cnt > maxx){
maxx = cnt;
pos = i;
}
}
}
printf("%d\n",pos);
}
return 0;
}