HDOJ 3861 The King’s Problem
2016-04-11 22:36
351 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861
这题题目很短啊,但是可能就是有那么两句话读不懂这题就会让你完全没有思路
What’s more, for each pair of city (u, v), if there is one way to go from u to v and go from v to u, (u, v) have to belong to a same state
And the king must insure that in each state we can ether go from u to v or go from v to
u between every pair of cities (u, v) without passing any city which belongs to other state
就是这两句话,小编我来翻译一下,第二句的意思是是说如果两个城市在都能够到达对方且不的话那么经过的城市一定也是属于同一个州里,这句话的言外之意就是说一个强连通分量都是在一个州的划分中,第一句话如果两个城市其中一个城市能够到达对方那么一定是属于同一个州,起初小编我并没有什么想法,看了一下样例才有点明白,样例中1->2,1->3,起初怎么想都觉得应该是一个啊,后来才想到,其实意思是一个州的两个城市必定可以从一个到达另一个,1只能匹配2和3的其中一个,所以是两个。这里应该差不多就可以想到这是二分图的最大匹配。先可以用Tarjan算法求出强连通,再缩点建图(DAG),再根据缩点求出最大匹配数,缩点数-最大匹配就是我们要得的答案。
这题题目很短啊,但是可能就是有那么两句话读不懂这题就会让你完全没有思路
What’s more, for each pair of city (u, v), if there is one way to go from u to v and go from v to u, (u, v) have to belong to a same state
And the king must insure that in each state we can ether go from u to v or go from v to
u between every pair of cities (u, v) without passing any city which belongs to other state
就是这两句话,小编我来翻译一下,第二句的意思是是说如果两个城市在都能够到达对方且不的话那么经过的城市一定也是属于同一个州里,这句话的言外之意就是说一个强连通分量都是在一个州的划分中,第一句话如果两个城市其中一个城市能够到达对方那么一定是属于同一个州,起初小编我并没有什么想法,看了一下样例才有点明白,样例中1->2,1->3,起初怎么想都觉得应该是一个啊,后来才想到,其实意思是一个州的两个城市必定可以从一个到达另一个,1只能匹配2和3的其中一个,所以是两个。这里应该差不多就可以想到这是二分图的最大匹配。先可以用Tarjan算法求出强连通,再缩点建图(DAG),再根据缩点求出最大匹配数,缩点数-最大匹配就是我们要得的答案。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <stack> using namespace std; const int maxn = 5000+10; int gn, gm; vector<int> G[maxn]; // for original graph. vector<int> G2[maxn];// for DAG. int dfs_clock, scc_cnt, sccno[maxn]; int DFN[maxn], Low[maxn]; stack<int> S; int linker[maxn]; bool used[maxn]; void init() { for(int i = 0; i < maxn; i++) { G[i].clear(); G2[i].clear(); } } void Tarjan(int u) { DFN[u] = Low[u] = ++dfs_clock; S.push(u); for(int i = 0; i < (int)G[u].size(); i++) { int v = G[u][i]; if(!DFN[v]) { Tarjan(v); Low[u] = min(Low[u], Low[v]); } else if(!sccno[v]) Low[u] = min(Low[u], DFN[v]); } if(DFN[u] == Low[u]) { scc_cnt++; for(;;) { int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc(int n) { dfs_clock = scc_cnt = 0; memset(DFN, 0, sizeof(DFN)); memset(sccno, 0, sizeof(sccno)); memset(Low, 0, sizeof(Low)); for(int i = 1; i <= gn; i++) if(!DFN[i]) Tarjan(i); } void build_map() { int u, v; for(int i = 1; i <= gn; i++) { for(int j = 0; j < (int)G[i].size(); j++) { u = sccno[i]; v = sccno[G[i][j]]; if(u != v) { G2[u].push_back(v); //printf("%d -> %d\n", u, v); // check if G2[] is correct. } } } } bool DFS(int x) { int v; for(int i = 0; i < (int)G2[x].size(); i++) { v = G2[x][i]; if(!used[v]) { used[v] = true; if(linker[v] == -1 || DFS(linker[v])) { linker[v] = x; return true; } } } return false; } int hungary() { int res = 0; memset(linker, -1, sizeof(linker)); for(int i = 1; i <= scc_cnt; i++) { memset(used, 0, sizeof(used)); if(DFS(i)) ++res; } return res; } int main() { int T, u, v; scanf("%d", &T); while(T--) { scanf("%d%d", &gn, &gm); init(); for(int i = 1; i <= gm; i++) { scanf("%d%d", &u, &v); G[u].push_back(v); } find_scc(gn); // for(int i = 1; i <= gn; i++) // printf("sccno[%d] = %d\n", i, sccno[i]); build_map(); int res = hungary(); printf("%d\n", scc_cnt-res); } return 0; }
相关文章推荐
- bzoj2588: Spoj 10628. Count on a tree
- C#贪吃蛇(WPF版)
- 自定义Dialog的简单实现
- C语言函数
- C++实现读取特定路径下文件夹及文件名的方法
- HTTP Keep-Alive详解
- 设计模式六大原则(5):迪米特法则
- JQuery和UpdatePannel的问题
- Windows内核读书笔记——SEH结构化异常处理
- 在Ubuntu中清理Network下Connect to Server的入口
- java面试题------40个Java集合面试问题和答案
- Windows驱动开发(3) - 内核模式下的字符串操作
- 网络流的征程——Ford-Fulkerson算法
- java面试题------40个Java集合面试问题和答案
- Android Connectivity分析(1)- ConnectivityManager
- OS中常用的调度算法总结
- Secure CRT键盘自我习惯
- shiro 的role 角色权限控制简单demo论述
- identity natiive assigned
- andorid 手机外部储存