大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学,你能帮帮他吗?
Input
本题有多组数据。第一行 T 表示数据组数。每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0
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
强连通:有向图 G 中任意两个结点连通
强连通分量(SCC):极大的强连通子图
Kosaraju算法求强联通分量:
第一遍 dfs 确定原图的逆后序序列。
第二遍 dfs 在反图中按照逆后序序列进行遍历 ,每次由起点遍历到的点即构成一个 SCC。
根据输入的边生成图G1和反图G2,使用Kosaraju算法求出强联通分量。
缩点,遍历所有顶点,对于点u,遍历他的所有边(u,v),如果u,v不再同一个强联通分量,则u所在的强联通分量和v所在的强联通分量间存在一条边。
缩点后,不难发现对于属于第 i 个 SCC 的点来说,答案分为 两部分,令 SCC[i] 表示第 i 个 SCC 中点的个数 (在Kosaraju算法第二次dfs遍历时求出)
当前 SCC 中的点,ans += SCC[i] – 1(去除自己)
其它 SCC 中的点 SUM ( SCC[j] ),其中 j 可到达 i
最后答案一定出现在出度为 0 的 SCC 中, 因此对每个出度为 0 的点进行 dfs,计算其能到达的点的 SUM(SCC[j]),即可得到答案。
#include
#include
#include
#include
#define N 5010
using namespace std;
struct edge
{
int v;
int net;
};
int head[N],head2[N],head3[N],dfn[N],c[N],vis[N];
int scc[N],ans[N],outdeg[N];
int dcnt,scnt;
edge e[30050],e2[30050],e3[30050];
int index,index2,index3;
int n,m,x;
void add(int u, int v)
{
e[index].v = v;
e[index].net = head[u];
head[u] = index;
index++;
}
void add2(int u, int v)
{
e2[index2].v = v;
e2[index2].net = head2[u];
head2[u] = index2;
index2++;
}
void add3(int u, int v)
{
e3[index3].v = v;
e3[index3].net = head3[u];
head3[u] = index3;
index3++;
}
void dfs1(int s)
{
vis[s] = 1;
for(int i=head[s]; i!=-1; i=e[i].net)
{
int v=e[i].v;
if(vis[v]==0)
{
dfs1(v);
}
}
dfn[++dcnt] = s;//dfs后序列中第dcnt个点为s
}
void dfs2(int s)
{
c[s] = scnt;//s在scnt号联通分量
scc[scnt]++;
for(int i=head2[s]; i!=-1; i=e2[i].net)
{
int v=e2[i].v;
if(c[v]==0)
dfs2(v);
}
}
void kosaraju()
{
dcnt=scnt=0;
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
memset(scc,0,sizeof(scc));
for(int i=1; i<=n; i++)
if(vis[i]==0)
dfs1(i);
for(int i=n; i>=1; i--)
{
if(c[dfn[i]]==0)
{
++scnt;
dfs2(dfn[i]);
}
}
}
void dfs3(int s)//计算得票数
{
vis[s]=1;
x += scc[s];
for(int i=head3[s];i!=-1;i=e3[i].net)
{
if(!vis[e3[i].v])
dfs3(e3[i].v);
}
}
int main()
{
int t=0;
scanf("%d",&t);
for(int i=1;i<=t; i++)
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(head2,-1,sizeof(head2));
memset(head3,-1,sizeof(head3));
memset(outdeg,0,sizeof(outdeg));
memset(ans,0,sizeof(ans));
index3= 0;
index2= 0;
index = 0;
while(m--)
{
int p1,p2;
scanf("%d%d",&p1,&p2);
p1++;
p2++;
add(p1,p2);
add2(p2,p1);
}
kosaraju();
//缩点
for(int j=1; j<=n; j++)
{
for(int k=head[j]; k!=-1; k=e[k].net)
{
if(c[j]!=c[e[k].v])
{
add3(c[e[k].v],c[j]);
outdeg[c[j]]++;//出度
}
}
}
int max=0;
for(int j=1; j<=scnt; j++)
{
if(outdeg[j] == 0)
{
x=0;
memset(vis,0,sizeof(vis));
dfs3(j);
ans[j] = x;
if(x > max)
max = x;
}
}
printf("Case %d: %d\n",i,max-1);
bool first=true;
for(int j=1; j<=n; j++)
{
if(ans[c[j]] == max)
{
if(first)
first = false, printf("%d",j-1);
else
printf(" %d",j-1);
}
}
printf("\n");
}
}