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\n",path.size());
    for(auto p : path) printf("%d %d\n",p.first,p.second);
}
int main(){
    int tt;
    for(scanf("%d",&tt); tt; tt--) solve();
    return 0;
}
HDU5740 Glorious Brilliance【最短路 KM匹配】的更多相关文章
- Glorious Brilliance  (最短路 + 带权二分图匹配)
		
这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建 ...
 - 【转】KM匹配题集
		
转自:http://blog.csdn.net/shahdza/article/details/7779324 [HDU]2255 奔小康赚大钱 模板题★1533 Going Home 模板题★242 ...
 - HDU 5740 - Glorious Brilliance
		
题意: 给出已0 1染色的无向图(不一定联通),一次操作为一对相邻点颜色互换. 问使任意相邻点颜色不同,最少需要多少次操作 分析: 交换两点的代价即为两点间最短路. 故用BFS找出所有点到任意点的最短 ...
 - KM匹配板子
		
/* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> ...
 - 【转载】图论 500题——主要为hdu/poj/zoj
		
转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...
 - 【HDOJ图论题集】【转】
		
=============================以下是最小生成树+并查集====================================== [HDU] How Many Table ...
 - hdu图论题目分类
		
=============================以下是最小生成树+并查集====================================== [HDU] 1213 How Many ...
 - HDU图论题单
		
=============================以下是最小生成树+并查集====================================== [HDU] 1213 How Many ...
 - POJ 2516 Minimum Cost (KM最优匹配)
		
题意:有N家家店,每家店都对K种货物有需求:同时有M家仓库,对K钟货物有供应.对于每种货物,每个仓库送至每家店都有自己的单位费用.求满足所有店所有货物的最小费用 分析:对于每一种货物,如果总需求大于总 ...
 
随机推荐
- 【Azure Redis 缓存】Azure Redis功能性讨论
			
关于使用Azure Redis服务在以下九大方面的功能性的解说: 高可用 备份可靠性 配置自动化 部署多样性 快速回档功能 数据扩容 SLA稳定性 数据安全性 监控系统 一:高可用 Azure Cac ...
 - Laya 踩坑日记-人物模型穿模,模型显示不正常
			
最近做游戏,人物要跑到很远的位置,z轴距离大概有20000个单位,然后就发现一个bug,到远处人物模型穿了,而且没办法改,这就尴尬了 Z轴对应值 0 100000 100000 当距离零点 ...
 - 【Spring】Spring 事务控制
			
Spring 事务控制 Spring 事务控制介绍 JavaEE 体系进行分层开发,事务控制位于业务层,Spring 提供了分层设计业务层的事务处理解决方案. Spring 的事务控制都是基于 AOP ...
 - 【Oracle】查看当前连接数和最大连接数
			
查看当前数据库连接数 select count(*) from v$session where username is not null; select count(*) from v$process ...
 - kubernets集群的安全防护(上)
			
一 了解认证机制 1.1 API的服务器在接收来自客户端的请求的时候会对发起的用户进行几个步骤 认证插件进行认证,确认发起的用户是外部用户,还是集群中的某个命名空间里面的pod 确认用户属于哪个 ...
 - 检查Mysql主从状态
			
.检查MySQL主从同步状态 #!/bin/bash USER=bak PASSWD=123456 IO_SQL_STATUS=$(mysql -u$USER -p$PASSWD -e show s ...
 - [Usaco2008 Mar]牛跑步
			
题目描述 BESSIE准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘, 然后走回牛棚. BESSIE也不想跑得太远,所以她想走最短的路经. 农场上一共有M (1 < ...
 - uni-app开发经验分享十七: 开发微信公众号(H5)JSSDK 的使用方式
			
因为这个jssdk被uni-app坑了好多天,作者说支持1.4版本,但是我用1.4的两个分享的新方法一直不支持. 最后只能放弃了,期待什么时候能更新上. 基本的使用方法:第一步 - 下载使用方式下载地 ...
 - LR_添加系统资源监控失败
			
1.服务开启情况:RPC.Rmote Resgistry.Network DDE.Server.Workstation.Network connection以上服务是否已开启 2.是否开了防火墙,如有 ...
 - C#高级编程第11版 - 第四章 索引
			
[1]4.2 继承的类型 1.C#不支持类的多继承,但它支持一个接口继承自多个接口. 2.单继承:单继承允许一个类继承自另外一个基类,C#支持. 3.多级继承:多级继承允许创建一个类继承自它的父类,而 ...