2013 ACM/ICPC Asia Regional Changsha Online - I Grand Prix
2013-09-23 00:14
447 查看
离正解非常非常接近就差一步的感觉真让人忧伤_(:3」∠)_
第一步肯定是求出最大匹配,数据范围挺大,连Dinic都超时,只能使用Hopcroft-Karp算法来求。
求出最大匹配ans后,先是一个朴素的想法。
枚举每条不是匹配的边(u,v),把它强行匹配,就是删去u,v两点,看新图的最大匹配数是否是ans-1,是的话它就可能出现在最大匹配中。
但这样的时间复杂度明显过大。
删去了u和v两点至多删去两个匹配,如果新图的匹配是ans-1就意味着u,v两点原来匹配的两点可以找到一条增广路径。
先假设用的就是dinic算法求的匹配,那么很明显的是(u,v)是最大匹配等价于有条从v到u的路,反之则有条从u到v的路。
所以每次询问u到v是否有路时,一定存在边(v,u),故问题等价于判断u与vv是否可以相互到达。
综上只需要把Hopcroft-Karp求出匹配的结果还原到网络流上,并在这个图上求出强连通分量,对于每条非匹配边,判断u和v不在一个SCC里面,
第一步肯定是求出最大匹配,数据范围挺大,连Dinic都超时,只能使用Hopcroft-Karp算法来求。
求出最大匹配ans后,先是一个朴素的想法。
枚举每条不是匹配的边(u,v),把它强行匹配,就是删去u,v两点,看新图的最大匹配数是否是ans-1,是的话它就可能出现在最大匹配中。
但这样的时间复杂度明显过大。
删去了u和v两点至多删去两个匹配,如果新图的匹配是ans-1就意味着u,v两点原来匹配的两点可以找到一条增广路径。
先假设用的就是dinic算法求的匹配,那么很明显的是(u,v)是最大匹配等价于有条从v到u的路,反之则有条从u到v的路。
所以每次询问u到v是否有路时,一定存在边(v,u),故问题等价于判断u与vv是否可以相互到达。
综上只需要把Hopcroft-Karp求出匹配的结果还原到网络流上,并在这个图上求出强连通分量,对于每条非匹配边,判断u和v不在一个SCC里面,
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second //#pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 40005 #define M 1000005 int n , m , p , s , t , ans; pair<int , int> ee[200000]; struct arc { int x , next; }e[M] , g[M]; int pre , mcnt , tmp , ncnt; void addarc(int x ,int y) { e[mcnt] = (arc) {y , pre[x]} , pre[x] = mcnt ++; } void addedge(int x ,int y) { g[ncnt] = (arc) {y , tmp[x]} , tmp[x] = ncnt ++; } int mx , my ; queue<int> que; int dx , dy ; bool vis ; bool find(int x) { for (int i = pre[x] ; ~i ; i = e[i].next) { int y = e[i].x; if (!vis[y] && dy[y] == dx[x] + 1) { vis[y] = 1; if (!~my[y] || find(my[y])) { mx[x] = y , my[y] = x; return 1; } } } return 0; } int matching() { memset(mx , -1 , sizeof(mx)); memset(my , -1 , sizeof(my)); int ans = 0; while (1){ bool flag = 0; while (!que.empty()) que.pop(); memset(dx , 0 , sizeof(dx)); memset(dy , 0 , sizeof(dy)); for (int i = 0 ; i < n ; ++ i) if (!~mx[i]) que.push(i); while (!que.empty()) { int x = que.front(); que.pop(); for (int i = pre[x] ; ~i ; i = e[i].next) { int y = e[i].x; if (!dy[y]) { dy[y] = dx[x] + 1 ; if (~my[y]) que.push(my[y]) , dx[my[y]] = dy[y] + 1; else flag = 1; } } } if (!flag) break; memset(vis , 0 , sizeof(vis)); for (int i = 0 ; i < n ; ++ i) if (!~mx[i] && find(i)) ++ ans; } return ans; } int idx , scnt , low , DFN , bel ; stack<int> st; bool is ; void tarjan(int x) { int i , y; DFN[x] = low[x] = ++ idx; is[x] = 1 , st.push(x); for (i = tmp[x] ; ~i ; i = g[i].next) { y = g[i].x; if (!DFN[y]) { tarjan(y); low[x] = min(low[x] , low[y]); } else if (is[y]) low[x] = min(low[x] , DFN[y]); } if (DFN[x] == low[x]) { scnt ++; do { i = st.top() , st.pop(); is[i] = 0 , bel[i] = scnt; }while (x != i); } } char str[10]; vector<int> res; void work() { int i , j , x , y; scanf("%d%d",&m,&p); memset(pre , -1 , sizeof(pre)) , mcnt = 0; s = n + m , t = s + 1; for (i = 0 ; i < p ; ++ i) { scanf("%s" , str); x = y = 0; for (j = 0 ; j < 3 ; ++ j) { x <<= 5; if (isdigit(str[j])) x |= (str[j] - '0'); else x |= (str[j] - 'A' + 10); } for (j = 3 ; j < 6 ; ++ j) { y <<= 5; if (isdigit(str[j])) y |= (str[j] - '0'); else y |= (str[j] - 'A' + 10); } ee[i] = make_pair(x , y); addarc(x , n + y); } res.clear(); ans = matching(); memset(tmp , -1 , sizeof(tmp)) , ncnt = 0; for (i = 0 ; i < n ; ++ i) if (!~mx[i]) addedge(s , i); else addedge(i , s); for (i = n ; i < n + m ; ++ i) if (!~my[i]) addedge(i , t); else addedge(t , i); for (x = 0 ; x < n ; ++ x) for (i = pre[x] ; ~i ; i = e[i].next) if (mx[x] != e[i].x) addedge(x , e[i].x); else addedge(e[i].x , x); scnt = idx = 0; memset(low , 0 , sizeof(low)); memset(DFN , 0 , sizeof(DFN)); for (i = 0 ; i <= t ; ++ i) if (!DFN[i]) tarjan(i); for (i = 0 ; i < p ; ++ i) { x = ee[i].fi , y = ee[i].se; if (mx[x] == y + n) continue; if (bel[x] != bel[y + n]) res.push_back(i); } printf("%d\n" ,res.size()); for (i = 0 ; i < res.size() ; ++ i) { if (i) printf(" "); printf("%d" , res[i]); } printf("\n"); } int main() { //freopen("~input.txt" , "r" , stdin); //int _; scanf("%d\n",&_); while (_--) while (~scanf("%d",&n)) work(); return 0; }
相关文章推荐
- 2013 ACM/ICPC Asia Regional Changsha Online - J Candies
- 数学公式+矩阵快速幂-2013 ACM/ICPC Asia Regional Changsha Online H 题
- 2013 ACM/ICPC Asia Regional Changsha Online
- 2013 ACM/ICPC Asia Regional Changsha Online - E
- ZOJ 2013 ACM/ICPC Asia Regional Changsha Online E Travel by Bike
- 2013 ACM/ICPC Asia Regional Changsha Online - G(DP)
- 2013 ACM/ICPC Asia Regional Changsha Online - C Color Representation Conversion
- zoj 数论之素数 2013 ACM/ICPC Asia Regional Changsha Online - G
- 2013 2013 ACM/ICPC Asia Regional Changsha Online - H Hypersphere
- 2013 ACM/ICPC Asia Regional Changsha Online - C(Color Representation Conversion)、E (Travelby Bi)解题报告
- 2013 ACM/ICPC Asia Regional Changsha Online - C(Color Representation Conversion)、E (Travelby Bi)解题报告
- 2013 ACM/ICPC Asia Regional Changsha Online–C (模拟)
- 2013 ACM/ICPC Asia Regional Changsha Online G Goldbach
- 数学+模拟-2013 ACM/ICPC Asia Regional Changsha Online J 题
- 数学计数-2013 ACM/ICPC Asia Regional Changsha Online-G 题
- 2013 ACM/ICPC Asia Regional Changsha Online Contest C
- 简记2013 ACM/ICPC Asia Regional Changsha Online
- 2013 ACM/ICPC Asia Regional Changsha Online J Candies
- 2013 ACM/ICPC Asia Regional Changsha Online J Candies
- 2013 ACM/ICPC Asia Regional Changsha Online - C Color Representation Conversion