题解:俺是菜鸟这题不会写,看题解的 点击打开链接
题目:一群人相互投票,票数可以传递,但是一个人只能从另一个人那里获得一张票,比如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; }