链接:http://acm.hdu.edu.cn/showproblem.php?pid=3639
题意:有n个人,m条边,每条边代表u给v投一票,票可以传递,比如A->B,B->C,这时C可以得到2票,求出得到最大票数的人有哪些。
分析:从一个强连通到另一个强连通分量的贡献为这两个强连通分量大小和减一。显然票数最大的人在图的端点。
将缩点后的图反向,可以得到一些入度为0的点,用DFS可以求出这些点的票数,最后去求出最大票数。
代码:
<pre name="code" class="cpp">#include <algorithm>
#include <iostream>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#define INF 0x3f3f3f3f
#define Mn 10010
#define Mm 200010
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul (u<<1)
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
int v,next;
} e[Mm],e2[Mm];
int tot,head[Mm],tot2,head2[Mm];
void addedge(int u,int v) {
e[tot].v=v;
e[tot].next=head[u];
head[u]=tot++;
}
void addedge2(int u,int v) {
e2[tot2].v=v;
e2[tot2].next=head2[u];
head2[u]=tot2++;
}
int tarjan_clock=0,scc_cnt=0;
int pre[Mn],sccno[Mn],lowlink[Mn];
int Mnx[Mn],minn[Mn],value[Mn];
stack<int> sk;
void Tarjan(int u) {
pre[u]=lowlink[u]=++tarjan_clock;
sk.push(u);
for(int i=head[u]; i!=-1; i=e[i].next) {
int v=e[i].v;
if(!pre[v]) {
Tarjan(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else if(!sccno[v])
lowlink[u]=min(lowlink[u],pre[v]);
}
if(lowlink[u]==pre[u]) {
scc_cnt++;
while(1) {
int x=sk.top();
sk.pop();
sccno[x]=scc_cnt;
if(x==u)
break;
}
}
}
void find_scc(int n) {
tarjan_clock=scc_cnt=0;
CLR(sccno,0);
CLR(pre,0);
for(int i=1; i<=n; i++) {
if(!pre[i]) Tarjan(i);
}
}
int vis[Mn];
int sum;
int sccnum[Mn];
void dfs(int u) {
sum+=sccnum[u];
vis[u]=1;
for(int i=head2[u]; ~i; i=e2[i].next) {
int v=e2[i].v;
if(!vis[v]) dfs(v);
}
}
void init() {
tot=tot2=0;
CLR(head,-1);
CLR(head2,-1);
}
int in[Mn];
int ans[Mn];
int a[Mn];
int main() {
int t;
scanf("%d",&t);
for(int cas=1; cas<=t; cas++) {
init();
int n,m;
scanf("%d%d",&n,&m);
while(m--) {
int u,v;
scanf("%d%d",&u,&v);
u++,v++;
addedge(u,v);
}
find_scc(n);
CLR(in,0);
CLR(sccnum,0);
for(int u=1; u<=n; u++) {
sccnum[sccno[u]]++;
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
if(sccno[u]!=sccno[v]) {
in[sccno[u]]++;
addedge2(sccno[v],sccno[u]);
}
}
}
CLR(ans,0);
int maxx=0;
for(int i=1; i<=scc_cnt; i++) {
if(in[i]==0) {
CLR(vis,0);
sum=0;
dfs(i);
ans[i]=sum;
maxx=max(sum,maxx);
}
}
int num=0;
for(int i=1; i<=n; i++) {
if(ans[sccno[i]]==maxx) {
a[num++]=i-1;
}
}
printf("Case %d: %d\n",cas,maxx-1);
for(int i=0; i<num-1; i++) {
printf("%d ",a[i]);
}
if(num)
printf("%d\n",a[num-1]);
else printf("\n");
}
return 0;
}