HDU3639 Hawk-and-Chicken :Tarjan缩点 +dfs+贪心
Description
一个N(0~n-1)个点与M条边的有向图,他们是有传递关系的,问对于图中哪些点是其他最多点能到达他的。
Input
第一行一个T,表示T组测试数据.
每组数据第一行为N,M
后面M行为两个正整数A,B,代表A到B有一条有向边.
Output
对应每组数据输出若干个答案.
Sample Input
2
4 3
3 2
2 0
2 1
3 3
1 0
2 1
0 2
Sample Output
Case 1: 2
0 1
Case 2: 2
0 1 2
HINT
题解
可以先缩点,再建一个每个连通块的反向图,这样最多的点肯定是出度为0的点。很容易证明。
如果假设最大值存在于一个入度不为0的分量中,那么连接这个分量的 那个分量票数支持肯定大于这个分量,假设不成立。
用dfs逐个搜索一遍就可以。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <stack>
#include <algorithm>
#include <cstring>
#include <climits>
#include<vector>
#define MAXN 7000
#define MAXM 60000+10
#define M(x) memset(x,0,sizeof(x))
using namespace std;
int T;
struct Edge{
int next,from,to,tnext;
};
struct G{
int head[MAXN],num,tail[MAXN];
Edge edge[MAXM*2];
void add(int from,int to)
{
edge[++num].next=head[from];
edge[num].tnext=tail[to];
edge[num].from=from;
edge[num].to=to;
head[from]=num;tail[to]=num;
}
void e()
{
num=0;
M(head);M(tail);M(edge);
}
}g1,g2;
int n,m;
int low[MAXN],dfn[MAXN],dfnum,cnt[MAXN],col[MAXN],co,vis[MAXN],vis2[MAXN];
int ans[MAXN],ans2[MAXN],maxn;
vector<int> con[MAXN];
stack<int> st;
void tarjan(int x)
{
dfn[x]=low[x]=++dfnum;vis[x]=1;st.push(x);
for(int i=g1.head[x];i;i=g1.edge[i].next)
{
if(!dfn[g1.edge[i].to])
{
tarjan(g1.edge[i].to);
low[x]=min(low[x],low[g1.edge[i].to]);
}else if(vis[g1.edge[i].to]) low[x]=min(low[x],dfn[g1.edge[i].to]);
}
if(low[x]==dfn[x])
{
int t=1;col[x]=++co;vis[x]=0;
con[co].push_back(x);
while(st.top()!=x)
{con[co].push_back(st.top());t++;vis[st.top()]=0;col[st.top()]=co;st.pop();}
st.pop();cnt[co]=t;
}
}
int cu[MAXN];
int dfs(int x)
{
vis2[x]=1;
int sum=0;
for(int i=g2.tail[x];i;i=g2.edge[i].tnext)
if(!vis2[g2.edge[i].from])
{
sum+=cnt[g2.edge[i].from]+
dfs(g2.edge[i].from);
}
return sum;
}
void init()
{
maxn=co=dfnum=0;
g1.e();g2.e();M(ans);M(ans2);M(cnt);M(col);
M(con);M(vis);M(vis2);M(low);M(dfn);M(cu);
while(st.size()) st.pop();
}
int main()
{
scanf("%d",&T);
for(int o=1;o<=T;o++)
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
g1.add(x+1,y+1);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=m;i++)
{
if(col[g1.edge[i].from]!=col[g1.edge[i].to])
g2.add(col[g1.edge[i].from],col[g1.edge[i].to]),
cu[col[g1.edge[i].from]]++;
}
for(int i=1;i<=co;i++)
{
if(!cu[i])
{M(vis2);ans2[i]=dfs(i)+cnt[i]-1;maxn=max(maxn,ans2[i]);}
}
for(int i=1;i<=co;i++)
{
if(ans2[i]==maxn)
for(int j=0;j<cnt[i];j++) ans[++ans[0]]=con[i][j];
}
sort(ans+1,ans+ans[0]+1);
printf("Case %d: %d\n",o,maxn);
printf("%d",ans[1]-1);
for(int i=2;i<=ans[0];i++)
printf(" %d",ans[i]-1);
printf("\n");
}
return 0;
}