HDU 3639 Hawk-and-Chicken 强连通分量分解 + dfs
2016-04-29 23:20
351 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3639
题意:大概意思是n个人投票,求获胜者得到多少票,并输出所有获胜者,其中支持关系是可以传递的,即a -> b, b -> c, c -> d,那么有a->d
思路:求强连通分量缩点,代表最终获胜的人所在强连通分量代的点出度必定为0,剩下的就是统计了,然后就比较坑了,刚开始我用的拓扑排序去统计,结果GG了,于是去找数据,结果发现在这里用拓扑排序搞不定,最后百度了一下:缩点后反向建图,那么最终获胜的人所在强连通分量代的点入度为0,于是以入度为0的点为起点dfs去统计支持他的人数。至于为什么反向建图,因为正向建图统计支持者太坑,反向只需dfs一遍统计即可。
总结:刚开始看着好简单。。。结果是个坑。。。
题意:大概意思是n个人投票,求获胜者得到多少票,并输出所有获胜者,其中支持关系是可以传递的,即a -> b, b -> c, c -> d,那么有a->d
思路:求强连通分量缩点,代表最终获胜的人所在强连通分量代的点出度必定为0,剩下的就是统计了,然后就比较坑了,刚开始我用的拓扑排序去统计,结果GG了,于是去找数据,结果发现在这里用拓扑排序搞不定,最后百度了一下:缩点后反向建图,那么最终获胜的人所在强连通分量代的点入度为0,于是以入度为0的点为起点dfs去统计支持他的人数。至于为什么反向建图,因为正向建图统计支持者太坑,反向只需dfs一遍统计即可。
总结:刚开始看着好简单。。。结果是个坑。。。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; typedef long long ll; const int N = 5010; const int INF = 0x3f3f3f3f; struct edge { int to, next; } G[N*10], e; int dfn , low , scc , st , ans ; int head , cost ; int index, cnt, num, top; bool vis , used ; vector<int> gra ; int n, m, sum = 0, x = 0; void init() { memset(head, -1, sizeof head); memset(dfn, -1, sizeof dfn); memset(vis, 0, sizeof vis); memset(ans, 0, sizeof ans); memset(cost, 0, sizeof cost); index = cnt = num = top = 0; } void add_edge(int v, int u) { G[cnt].to = u; G[cnt].next = head[v]; head[v] = cnt++; } void tarjan(int v) { dfn[v] = low[v] = index++; vis[v] = true; st[top++] = v; int u; for(int i = head[v]; i != -1; i = G[i].next) { u = G[i].to; if(dfn[u] == -1) { tarjan(u); low[v] = min(low[v], low[u]); } else if(vis[u]) low[v] = min(low[v], dfn[u]); } if(dfn[v] == low[v]) { num++; do { u = st[--top]; vis[u] = false; scc[u] = num; ans[num]++; } while(u != v); } } void dfs(int v) { used[v] = true; sum += ans[v]; for(int i = 0; i < gra[v].size(); i++) if(! used[gra[v][i]]) dfs(gra[v][i]); } void slove() { for(int i = 0; i < n; i++) if(dfn[i] == -1) tarjan(i); int indeg ; memset(indeg, 0, sizeof indeg); for(int i = 0; i <= num; i++) gra[i].clear(); for(int i = 0; i < n; i++) for(int j = head[i]; j != -1; j = G[j].next) if(scc[i] != scc[G[j].to]) { /*反向建图*/ indeg[scc[i]]++; gra[scc[G[j].to]].push_back(scc[i]); } int Max = -1; for(int i = 1; i <= num; i++) if(indeg[i] == 0) /*统计入度为0的点的支持者*/ { memset(used, 0, sizeof used); sum = 0; dfs(i); cost[i] = sum; Max = max(Max, sum); } int k = 0, res ; for(int i = 1; i <= num; i++) if(cost[i] == Max) /*统计获胜者*/ for(int j = 0; j < n; j++) if(scc[j] == i) res[k++] = j; sort(res, res + k); printf("Case %d: %d\n", ++x, Max - 1); for(int i = 0; i < k; i++) if(i == 0) printf("%d", res[i]); else printf(" %d", res[i]); printf("\n"); } int main() { int t, a, b; scanf("%d", &t); while(t--) { init(); scanf("%d%d", &n, &m); for(int i = 0; i < m; i++) { scanf("%d%d", &a, &b); add_edge(a, b); } slove(); } return 0; }
相关文章推荐
- 机器学习里面常用知识
- 俄罗斯方块
- 在hadoop环境下用spark跑wordcount(没有安装scala)
- Swift之字符串的介绍
- Java mail API学习
- stack queue deque 用法
- goahead 移植与配置---fwqlzz love is for ever
- Linux CentOS 7 YouCompleteMe相关配置。
- java的数据类型
- HDU 2018 母牛的故事(递推)
- 3月23日作业
- Java语言中,求数组中的最大值
- 求两点之间的距离
- windows常用快捷键
- 程序员的自我修养第三章笔记
- 找到环状序列的最小字典表示
- poj 2826(好坑,线段相交问题)
- hiho 57 高斯消元 二
- 【深度优先搜索】种族部落
- 正整数的打印