zoukankan      html  css  js  c++  java
  • 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;
    }
    more crazy more get!
  • 相关阅读:
    alias 命令
    iptables 命令
    unzip 命令
    gzip 命令
    zip 命令
    tar 命令
    nslookup 命令
    dig 命令
    java 线程池
    java 线程
  • 原文地址:https://www.cnblogs.com/wethura/p/9771743.html
Copyright © 2011-2022 走看看