题意
大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学,你能帮帮他吗?
Input
本题有多组数据。第一行 T 表示数据组数。每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0 <m <= 30000),接下来有 M 行包含两个整数 A 和 B(A != B) 表示 A 认为 B 合适。
Output
对于每组数据,第一行输出 “Case x: ”,x 表示数据的编号,从1开始,紧跟着是最高的票数。 接下来一行输出得票最多的同学的编号,用空格隔开,不忽略行末空格!
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
思路
本题考察强连通分量,采用kosaraju算法来找到所有的强连通分量
在存图的时候不仅要存原图,还要存反图,为了从DFS逆后序序列中进行反图DFS时确定出所有的SCC
首先经过一次DFS找到DFS的后序序列
然后将后序序列反向进行反图的DFS,此时由起点到达的所有点构成一个SCC
统计每个SCC的中的人数存到num数组中
之后再对原图进行一次DFS,确定所有能到达某一个SCC的所有SCC存入pre数组中
之后找到出度为0的点a(出度为0的人,支持他的人数最多),对于此点所在的SCC i,tmp数组存储支持他的人数,temp[a]+=num[i]-1
对于pre[i]中的SCC j:temp[a]+=num[j]
最后统计出得票最高的票数 ma,再将票数为ma的人的编号全部输出即可
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int maxn=5100;
int n,c[maxn],dfn[maxn],vis[maxn],dcnt,scnt,num[maxn],n1[maxn];
//dcnt-dfs序计数,scnt-scc计数
//dfn[i]-dfs后序列中第i个数
//c[i]-i号节点所在scc编号
//num-票数,n1-每个scc的人数
vector<int> g1[maxn],g2[maxn],pre[maxn];//g1-原图,g2-反图,pre-到达此scc的scc序号
void dfs1(int x)
{
vis[x]=1;
for(int i=0;i<g1[x].size();i++)
if(!vis[g1[x][i]])
dfs1(g1[x][i]);
dfn[++dcnt]=x;
}
void dfs2(int x)
{
c[x]=scnt;
for(int i=0;i<g2[x].size();i++)
if(!c[g2[x][i]])
dfs2(g2[x][i]);
}
void dfs3(int x)
{
vis[x]=2;
for(int i=0;i<g1[x].size();i++)
{
vector<int>::iterator find1=find(pre[c[g1[x][i]]].begin(),pre[c[g1[x][i]]].end(),c[x]);
if(c[g1[x][i]]!=c[x]&&find1==pre[c[g1[x][i]]].end())
pre[c[g1[x][i]]].push_back(c[x]);
if(vis[g1[x][i]]!=2)
dfs3(g1[x][i]);
}
}
void nu(int tmp,int x,int vi[])
{
for(int i=0;i<pre[x].size();i++)
{
if(!vi[pre[x][i]])
{
vi[pre[x][i]]=1;
num[tmp]+=n1[pre[x][i]];
nu(tmp,pre[x][i],vi);
}
}
}
void k()
{
dcnt=scnt=0;
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
for(int i=0;i<n;i++)
if(!vis[i])
dfs1(i);
for(int i=n-1;i>=0;i--)
if(!c[dfn[i]])
{
++scnt;
dfs2(dfn[i]);
}
for(int i=0;i<n;i++)
if(vis[i]!=2)
dfs3(i);
}
int main()
{
int t;
scanf("%d",&t);
for(int l=1;l<=t;l++)
{
int m;
scanf("%d%d",&n,&m);
for(int i=0;i<=n+4;i++)
{
g1[i].clear();
g2[i].clear();
pre[i].clear();
}
int a,b;
while(m--)
{
scanf("%d%d",&a,&b);
g1[a].push_back(b);
g2[b].push_back(a);
}
k();
memset(n1,0,sizeof(n1));
for(int i=1;i<=scnt;i++)
for(int j=0;j<n;j++)
if(c[j]==i)
n1[i]++;
for(int i=0;i<n;i++)
{
num[i]+=n1[c[i]]-1;
int vi[scnt];
memset(vi,0,sizeof(vi));
vi[c[i]]=1;
nu(i,c[i],vi);
}
int ma=-1;
for(int i=0;i<n;i++)
ma=max(ma,num[i]);
printf("Case %d: %d\n", l, ma);
int tmp[maxn],co=0;
for(int i=0;i<n;i++)
if(num[i]==ma)
tmp[co++]=i;
for(int i=0;i<co;i++)
{
if(i<co-1)
printf("%d ",tmp[i]);
else
printf("%d",tmp[i]);
}
printf("\n");
}
return 0;
}