题目
大学班级选班长,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
题目思路
思想:强连通分量 缩点
实现:通过强连通分量实现缩点,同一个强连通分量中的所有学生内部投票数相等(=n-1)
一个学生的得票数=内部得票数+其他与之相连的强连通分量的票数
对于内部得票数:
等于内部人数-1
对于外部得票数:
等于其他指向这个学生所在的连通分量的连通分量的人数
过程:
构建原图和反向图
fedge和dedge
计算出每个节点对应的连通分量
利用dfs计算出图的后序序列
根据逆后序序列遍历反向图,构建强连通分量
根据构建出的强连通分量进行缩点得到缩点后的图ledge,并记录下缩点后对应的内部节点个数
遍历每一个节点,通过dfs利用连通分量计算得到的投票数
找出最大投票数ansmax,并找出所有与ansmax相等的节点,输出
总结:这个题需要用到的数组和数比较多,在写的时候要注意思路清晰;同时,由于是多组数据,一定要确保数组和数初始化正确(提交发生了re原因就是有个数值没有进行初始化)
AC代码
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=5005;
const int maxm=30010;
struct node{
int to,nex;
}fedge[maxm],dedge[maxm],ledge[maxm];
int fhead[maxn],dhead[maxn],lhead[maxn],ans[maxn];
int vis[maxn],score[maxn],scc[maxn],lvis[maxn],dfn[maxn];
int m,n,N,t,fnum,dnum,lnum,dcnt,scnt,ansmax;
void add(int x,int y,node *edge,int *head,int &num)
{
num++;
edge[num].to=y;
edge[num].nex=head[x];
head[x]=num;
}
void lastedge()
{
map<pair<int,int>,int> record;
int ink[maxn];
memset(ink,0,sizeof(ink));
for(int x=0;x<n;x++)
for(int i=fhead[x];i!=-1;i=fedge[i].nex){
int y=fedge[i].to;
int a=scc[x];int b=scc[y];
if(record.find(make_pair(a,b))!=record.end()) continue;
if(scc[y]!=scc[x]){
add(scc[y],scc[x],ledge,lhead,lnum);
record[make_pair(scc[y],scc[x])]=1;
}
}
}
void dfs1(int s)
{
vis[s]=1;
for(int i=fhead[s];i!=-1;i=fedge[i].nex)
if(!vis[fedge[i].to]) dfs1(fedge[i].to);
dfn[++dcnt]=s;
}
void dfs2(int s)
{
scc[s]=scnt;
score[scnt]++;
for(int i=dhead[s];i!=-1;i=dedge[i].nex)
if(!scc[dedge[i].to]) dfs2(dedge[i].to);
}
void kosaraju()
{
dcnt=scnt=0;
memset(scc,0,sizeof(scc));
memset(vis,0,sizeof(vis));
memset(score,0,sizeof(score));
memset(dfn,0,sizeof(dfn));
for(int i=0;i<n;i++)
if(!vis[i]) dfs1(i);
for(int i=n;i>=1;i--)
if(!scc[dfn[i]]) ++scnt,dfs2(dfn[i]);
}
void dfs3(int s,int u)
{
lvis[u]=1;
for(int j=lhead[u];j!=-1;j=ledge[j].nex){
int y=ledge[j].to;
if(!lvis[y])
{
ans[s]+=score[y];
lvis[y]=1;
dfs3(s,y);
}
}
}
void init()
{
memset(fhead,-1,sizeof(fhead));
memset(lhead,-1,sizeof(lhead));
memset(dhead,-1,sizeof(dhead));
memset(ans,0,sizeof(ans));
fnum=0;dnum=0;lnum=0;
ansmax=0;
}
int main()
{
cin>>N;t=1;
while(N--)
{
init();
cin>>n>>m;
for(int i=0;i<m;i++)
{
int u,v;
cin>>u>>v;
add(u,v,fedge,fhead,fnum);//原图
add(v,u,dedge,dhead,dnum);//反向图
}
kosaraju();
lastedge();
for(int i=1;i<=scnt;i++)
{
memset(lvis,0,sizeof(lvis));
ans[i]+=score[i]-1;
dfs3(i,i);
}
for(int i=1;i<=scnt;i++)
ansmax=max(ansmax,ans[i]);
cout<<"Case "<<t++<<": "<<ansmax<<endl;
bool flag=true;
for(int i=0;i<n;i++)
{
if(ans[scc[i]]==ansmax){
if(flag) flag=false,cout<<i;
else cout<<" "<<i;
}
}
cout<<endl;
}
return 0;
}