题解:俺是菜鸟这题不会写,看题解的 点击打开链接
题目:一群人相互投票,票数可以传递,但是一个人只能从另一个人那里获得一张票,比如0->1 1->2 0->2
2获得的票数最多,有2张。求哪一些人获得的票数最多?
解题 :targin缩点后 得到一个DAG(有向无环图,顺便记录下每个强连通图包含的节点数),每个强连通图可以用一个唯一编号去代替,这样可以知道有多少个强连通图是没有出度的,我们的答案就在这些 没有出度的强连通图中。因为如果一个强连通图有出度,那么它一定不是得票最多的。
这样我们的问题就转化为: 求各个 没有出度的强连通图 能够让多少个 节点 汇聚到这里。为了方便我们统计,可以建立一个反图(节点和原图相同,但是边的方向全部相反),这时候原图出度为0的点,就变成了反图中 入度为0 的点,所以我们只需要对反图中所有 入度为 0 的强连通图 进行 bfs/dfs ,就可以得到有多少个 节点 可以汇聚到当前这个入度为0 的强连通图,最后比较取最大max,输出最大是max-1(去掉强连通图中的自己,自己不能投给自己)。至于最后输出强连通图中的节点就好办了,从小到大遍历每个节点0~n-1,判断它所在的连通图 可汇聚的节点数是不是max ,是的话就输出。
自己脑瓜不好使,想不建立反向图,直接用拓扑排序,但是wa了很久,算了,以后有时间再看看吧。
//targin+缩点+反向图 5000节点 30000边 限时2000ms 提交600ms
#include<stdio.h>
#include<queue>
#include<vector>
#include<set>
using namespace std;
int min(int a,int b)
{
return a<b?a:b;
}
const int sz = 5000+10;
int cnt;
struct Edge
{
int to;
int next;
};
int n,m;
Edge edge[30000+10];
int head[sz];
int dfn[sz],low[sz],time;
int stack[sz];
bool instack[sz];
int ss;
int sc;
int belong[sz];
int ans[sz];
int in[sz];
//vector<int>node[sz];
vector<int>G[sz];//反向图的邻接表
int dp[sz];//每个强联通图得到的支持人数
void addEdge(int from,int to)
{
edge[++cnt].next = head[from];
edge[cnt].to = to;
head[from] = cnt;
}
void targin(int u)
{
dfn[u] = low[u] = ++time;
stack[ss++] = u;
instack[u] = true;
for(int i=head[u];i;i=edge[i].next)
{
if(dfn[edge[i].to]==0)targin(edge[i].to);
if(instack[edge[i].to])low[u] = min(low[u],low[edge[i].to]);
}
if(low[u]==dfn[u])
{
sc ++;
int v;
int c = 0;
do
{
v = stack[--ss];
instack[v] = false;
belong[v] = sc;
// node[sc].push_back(v);
c++;
}while(v!=u);
ans[sc] = c;
}
}
int q[sz];
int qq;
int bfs(int u)
{
bool visit[sz] = {0};
int sum = 0;
q[qq++] = u;
visit[u] = 1;
while(qq>0)
{
int top = q[--qq];
sum = sum + ans[top];
for(int i=0;i<G[top].size();i++)
{
if(!visit[G[top][i]])
{
visit[G[top][i]] = true;
q[qq++]=G[top][i];
}
}
}
return sum;
}
void init()
{
sc = cnt = ss = time = qq = 0;
for(int i=0;i<=n;i++)
{
head[i] = 0;
instack[i] = false;
in[i] = 0;
G[i].clear();
dp[i] = 0;
dfn[i] = low[i] = 0;
// node[i].clear();
}
}
int main()
{
int t;
scanf("%d",&t);
int ca = 0;
while(ca<t)
{
ca ++;
scanf("%d %d",&n,&m);
init();
for(int i=1;i<=m;i++)
{
int from,to;
scanf("%d %d",&from,&to);
addEdge(from,to);
}
for(int i=0;i<n;i++)
{
if(dfn[i]==0)
{
targin(i);
}
}
for(int i=0;i<n;i++)
{
for(int j=head[i];j;j=edge[j].next)
{
if(belong[i]!=belong[edge[j].to])
{
in[belong[i]] ++;
G[belong[edge[j].to]].push_back(belong[i]);//邻接
}
}
}
int max = -1;
for(int i=1;i<=sc;i++)
{
if(in[i]==0)
{
int sum = bfs(i);
dp[i] = sum;
if(sum>max)
{
max = sum ;
}
}
}
printf("Case %d: %d\n",ca,max-1);
int flag = 0;
for(int i=0;i<n;i++)
{
if(dp[belong[i]]==max)
{
if(flag==0)
{
printf("%d",i);
flag = 1;
}else{
printf(" %d",i);
}
}
}
printf("\n");
}
return 0;
}