Glorious Brilliance (最短路 + 带权二分图匹配)
Posted wethura
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Glorious Brilliance (最短路 + 带权二分图匹配)相关的知识,希望对你有一定的参考价值。
这是一道代码大题。一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!!
把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建图,利用二分图KM算法去匹配最优方案。然后求出每一组更换的,利用原先已经求好的路径去储存答案。
#include<bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 5e2 + 7; vector<pair<int, int> >ANS; vector<int>Gra[maxn], path[maxn][maxn], X, Y, Left, Right; char str[maxn]; int g[maxn][maxn], col[maxn], *pairr, pairr1[maxn], pairr2[maxn]; int mp[maxn][maxn], lx[maxn], ly[maxn], linker[maxn], slack[maxn]; int n, m, l, nx, ny; bool vis[maxn], visx[maxn], visy[maxn]; bool DFS(int x){ visx[x] = true; for(int y = 0; y < ny; y++) { if(visy[y]) continue; int tmp = lx[x] + ly[y] - mp[x][y]; if(tmp == 0) { visy[y] = true; if(linker[y] == -1 || DFS(linker[y])) { linker[y] = x; return true; } } else if(slack[y] > tmp) slack[y] = tmp; } return false; } int KM(){ memset(linker,-1,sizeof(linker)); memset(ly,0,sizeof(ly)); for(int i = 0; i < nx; i++) { lx[i] = -inf; for(int j = 0; j < ny; j++) if(mp[i][j] > lx[i]) lx[i] = mp[i][j]; } for(int x = 0; x < nx; x++) { for(int i = 0; i < ny; i++) slack[i] = inf; while(true) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if(DFS(x)) break; int d = inf; for(int i = 0; i < ny; i++) if(!visy[i] && d > slack[i]) d = slack[i]; for(int i = 0; i < nx; i++) if(visx[i]) lx[i] -= d; for(int i = 0; i < ny; i++) { if(visy[i]) ly[i] += d; else slack[i] -= d; } } } int res = 0; for(int i = 0; i < ny; i++) if(linker[i] != -1) res -= mp[linker[i]][i]; return res; } void getMinRoad(int u){ queue<int>que;while(!que.empty())que.pop(); que.push(u);g[u][u] = 0; path[u][u].push_back(u); memset(vis, false, sizeof(vis)); vis[u] = true; while(!que.empty()){ int st = que.front();que.pop(); for(auto to : Gra[st]){ if(vis[to]) continue; vis[to] = true; g[u][to] = g[u][st] + 1; path[u][to] = path[u][st]; path[u][to].push_back(to); que.push(to); } } } bool color(int st){ queue<int> que;while(!que.empty())que.pop(); X.push_back(st); que.push(st); col[st] = 0; while(!que.empty()){ int u = que.front();que.pop(); for(auto v : Gra[u]){ if(col[v] == col[u]) return false; if(col[v] != -1) continue; col[v] = col[u] ^ 1; if(col[v]) Y.push_back(v); else X.push_back(v); que.push(v); } } return true; } void GetAns(int u, int v, int setp){ if(u == v) return ; vector<int>&tmp = path[u][v]; for(int i = 0; i < tmp.size() - 1; i ++) if(str[tmp[i]] != str[tmp[i +1]]){ ANS.push_back(make_pair(tmp[i], tmp[i + 1])); swap(str[tmp[i]], str[tmp[i + 1]]); GetAns(u, tmp[i], setp + 1); GetAns(tmp[i + 1], v, setp + 1); return ; } } int getSum(vector<int>A, vector<int>B, int Pair[]){ Left.clear(); Right.clear(); for(auto x : A) if(str[x] == ‘1‘) Left.push_back(x); for(auto x : B) if(str[x] == ‘0‘) Right.push_back(x); nx = ny = Left.size(); for(int i = 0; i < nx; i ++) for(int j = 0; j < ny; j ++) mp[i][j] = - g[Left[i]][Right[j]]; int ret = KM(); for(int i = 0; i < nx; i ++){ int u = Right[i], v = Left[linker[i]]; Pair[u] = v;Pair[v] = u; } return ret; } bool solve(int st){ int zero = 0, sum1 = inf, sum2 = inf; X.clear(), Y.clear(); if(!color(st)) return 0; for(auto x : X) if(str[x] == ‘0‘) zero ++; for(auto x : Y) if(str[x] == ‘0‘) zero ++; if(zero == X.size()) sum1 = getSum(X, Y, pairr1); if(zero == Y.size()) sum2 = getSum(Y, X, pairr2); if(sum1 == inf && sum2 == inf) return false; pairr = sum1 > sum2 ? pairr2 : pairr1; for(auto x : X) if(pairr[x] != -1) GetAns(x, pairr[x], 1); return true; } void init(){ memset(pairr1, -1, sizeof(pairr1)); memset(pairr2, -1, sizeof(pairr2)); memset(slack, 0, sizeof(slack)); for(int i = 1; i <= n; i ++){ Gra[i].clear(); col[i] = -1; for(int j = 1; j <= n; j ++){ g[i][j] = inf; path[i][j].clear(); } } ANS.clear(); } int main(){ int T,a,b;scanf("%d",&T); while(T --){ scanf("%d%d%s", &n, &m, str + 1); init(); for(int i = 0; i < m; i ++){ scanf("%d%d",&a,&b); Gra[a].push_back(b); Gra[b].push_back(a); } for(int i = 1; i <= n; i ++) getMinRoad(i); bool flag = true; for(int i = 1; i <= n; i ++){ if(col[i] == -1 && !solve(i)){ flag = false;break; } } if(!flag){ printf("-1 "); continue; } printf("%d ", ANS.size()); for(int i = 0; i < ANS.size(); i ++){ printf("%d %d ",ANS[i].first, ANS[i].second); } } return 0; }
以上是关于Glorious Brilliance (最短路 + 带权二分图匹配)的主要内容,如果未能解决你的问题,请参考以下文章