zoukankan      html  css  js  c++  java
  • HDU5740 Glorious Brilliance【最短路 KM匹配】

    HDU5740 Glorious Brilliance

    题意:

    给出一张不一定合法的染色图,每次可以交换相邻两点的颜色,问最少多少次能使染色图合法
    合法的染色图相邻点的颜色不能相同

    题解:

    首先要确定原图中是否存在染色图,如果不存在直接输出(-1)
    其次确定给定的两种颜色数量是否能够染出一张合法的染色图,如果数量不对输出(-1)

    可以发现对于节点(u,v),交换两者的颜色最少需要操作两者(dist_{u,v})次,并且可以保证路径中间点的颜色不变
    指针先指向最左边点,然后右指针向右找到第一个和左指针所指颜色不同的点,把右侧点不断和左边的点换,然后把左指针指向右指针所指点,继续操作

    所以我们需要将两种颜色的点两两匹配,使得最短路的和最小,用KM匹配即可,最后输出路径,就按上述方法输出即可
    注意要对每一块连通图单独处理

    view code
    //#pragma GCC optimize("O3")
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 555;
    const int INF = 0x3f3f3f3f;
    int n,m,col[MAXN],tpcol[MAXN],ID;
    int dist[MAXN][MAXN], pre[MAXN][MAXN];
    char buf[MAXN];
    vector<int> G[MAXN],pt[MAXN];
    
    bool setColor(int x, int id){                       // 染色
        queue<int> que;
        que.push(x);
        tpcol[x] = 0;
        while(!que.empty()){
            int u = que.front();
            que.pop();
            pt[id].push_back(u);
            for(int v : G[u]){
                if(tpcol[v]!=-1){
                    if(tpcol[v]==tpcol[u]) return false;
                    continue;
                }
                tpcol[v] = tpcol[u] ^ 1;
                que.push(v);
            }
        }
        return true;
    }
    void getPath(int x){                                // 计算最短路和最短路路径
        memset(dist[x]+1,0x3f,n<<2);
        dist[x][x] = 0;
        pre[x][x] = -1;
        queue<int> que;
        que.push(x);
        while(!que.empty()){
            int u = que.front();
            que.pop();
            for(int v : G[u]){
                if(dist[x][v]!=INF) continue;
                dist[x][v] = dist[x][u] + 1;
                pre[x][v] = u;
                que.push(v);
            }
        }
    }
    int match[MAXN],visx[MAXN],visy[MAXN],lx[MAXN],ly[MAXN],slack[MAXN];
    vector<int> lft,rht;
    bool dfs(int u){
        visx[u] = true;
        for(int v : rht){
            if(visy[v]) continue;
            int gap = dist[u][v] - lx[u] - ly[v];
            if(!gap){
                visy[v] = true;
                if(match[v]==-1 or dfs(match[v])){
                    match[v] = u;
                    return true;
                }
            }
            else slack[v] = min(slack[v],gap);
        }
        return false;
    }
    int KM(int id, int tag){
        lft.clear(); rht.clear();
        for(int x : pt[id]){
            if((col[x]^tag)==tpcol[x]) continue;
            if(col[x]==0) lft.push_back(x);
            else rht.push_back(x);
        }
        if(lft.size()!=rht.size()) return INF;
        for(int x : lft){
            lx[x] = INF;
            for(int y : rht) lx[x] = min(lx[x],dist[x][y]);
        }
        for(int x : rht){
            match[x] = -1;
            ly[x] = 0;
        }
        for(int x : lft){
            for(int y : rht) slack[y] = INF;
            while(true){
                for(int xx : lft) visx[xx] = false;
                for(int yy : rht) visy[yy] = false;
                if(dfs(x)) break;
                int d = INF;
                for(int yy : rht) if(!visy[yy]) d = min(d,slack[yy]);
                for(int xx : lft) if(visx[xx]) lx[xx] += d;
                for(int yy : rht){
                    if(!visy[yy]) slack[yy] -= d;
                    else ly[yy] -= d;
                }
            }
        }
        int tot = 0;
        for(int y : rht) tot += dist[y][match[y]];
        return tot;
    }
    vector<pair<int,int> > path;
    void record(int id, int tag){
        KM(id,tag);
        for(int y : rht){
            int x = match[y];
            vector<int> route;
            int u = y;
            while(u!=-1){
                route.push_back(u);
                u = pre[x][u];
            }
            int sz = (int)route.size();
            int l = 0;
            while(l!=sz-1){
                int r = l;
                while(col[route[r]]==col[route[r+1]]) r++;
                r++;
                for(int i = r; i > l; i--) path.push_back(make_pair(route[i],route[i-1]));
                swap(col[route[l]],col[route[r]]);
                l = r;
            }
        }
    }
    void solve(){
        scanf("%d %d %s",&n,&m,buf+1);
        for(int i = 1; i <= n; i++) col[i] = buf[i] - '0';
        for(int i = 1; i <= n; i++) G[i].clear();
        for(int i = 1; i <= n; i++) tpcol[i] = -1;
        for(int i = 1; i <= m; i++){
            int u, v; scanf("%d %d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        ID = 0;
        bool flag = false;
        for(int i = 1; i <= n; i++) getPath(i);
        path.clear();
        for(int i = 1; i <= n; i++) if(tpcol[i]==-1){
            pt[++ID].clear();
            if(!setColor(i, ID)){
                flag = true;
                break;
            }
            int c0 = 0, c1 = 0;
            int tpc0 = 0, tpc1 = 0;
            for(int x : pt[ID]){
                if(col[x]==0) c0++;
                else c1++;
                if(tpcol[x]==0) tpc0++;
                else tpc1++;
            }
            if(c0!=tpc0 and c0!=tpc1){
                flag = true;
                break;
            }
            int mt0 = INF, mt1 = INF;
            if(c0==tpc0) mt0 = KM(ID,0);
            if(c0==tpc1) mt1 = KM(ID,1);
            if(mt0==INF and mt1==INF){
                flag = true;
                break;
            }
            if(mt0<mt1) record(ID,0);
            else record(ID,1);
        }
        if(flag){
            puts("-1");
            return;
        }
        printf("%d
    ",path.size());
        for(auto p : path) printf("%d %d
    ",p.first,p.second);
    }
    int main(){
        int tt;
        for(scanf("%d",&tt); tt; tt--) solve();    
        return 0;
    }
    
  • 相关阅读:
    AM3715/DM3730 更改内存大小后kernel boot不起来的解决办法
    xslt转换xml文档&&xslt call java方法
    VSCode 运行go test显示打印日志
    tomcat作为windows服务的参数配置,特别是PermSize的设置
    高亮显示web页表格行
    深入分析 Java 中的中文编码问题
    webwork和spring多配置文件的方法
    Bug笔记:诡异的$.ajax
    C#多态
    委托的本质
  • 原文地址:https://www.cnblogs.com/kikokiko/p/13194925.html
Copyright © 2011-2022 走看看