HDU5740 Glorious Brilliance
来源:互联网 发布:淘宝店铺音乐代码 编辑:程序博客网 时间:2024/05/21 05:42
题目链接:点击打开链接
题目大意:给一个无向图(1<n<=500),每个点为黑色或者是白色,要求相邻的节点颜色不相同。现在有一种操作,交换两个相邻节点的颜色。问使得图颜色合法的最少操作数,并输出操作序列,如果不可能让图合法则输出-1。
解析:
当一个图有解时,确定任意一个节点的颜色,则其他节点的颜色均能确定,根据距离奇偶判定即可,那么一定有两种染色方案。
下面两种情况是不可能得到合法的染色的:
1.图中存在奇环。
2.错误的黑点个数不等于白点个数。所谓的错误的颜色就是指该位置本应为白(黑)色,实际为黑(白)色。
奇环可以通过一遍dfs判断。
如果两种染色方案的错误黑点个数均不等于错误白点个数,说明不可行,这也可以通过dfs判断。
要交换两个位置的点的颜色,并不产生其他影响,交换的最少操作数为两点在图上的最短路径。首先要交换的两个点颜色一定不相同,从某一点触发,需要和路径上的异色点交换,同色点不需要交换。再从另一端点返回,同样也是与异色点交换。
例如
1234567
0001011
需要将2和7位置互换。
交换序列为:
(3,4)(5,6)(6,7)(5,4)(3,2)
1234567
0101010
最短距离可以bfs得到,寻找点到点长度为k的最短路径可以暴力dfs找。剩下来的问题就是如何对错误的点进行交换,交换代价为最短路径,只需要跑一个带权匹配就可以了。注意,找到一个匹配的时候,需要两个端点染色更新,但不能直接更新到最终的染色中,因为有两种染色方案,所以需要比较两种方案,取更优的更新答案。
因为图可能不连通,所以对于每个连通块做一遍上述操作即可。
细节比较多...
#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>#include <cstdlib>#include <string>#include <cmath>#include <set>#include <map>#include <queue>#include <bitset>using namespace std;typedef long long ll;const int mod = 1000000007;const double eps = 1e-6;const int inf = 0x3f3f3f3f;const ll INF = 100000000000000000ll;const int MAXN = 505;const int MAXM = 310000;namespace MCMF{const static int N = 505;const static int M = 310000;int head[N], pre[N], cur[N], d[N], vis[N], s, e, no;struct point{int u, v, flow, next,cost;point(){};point(int x, int y, int z, int w, int c):u(x), v(y), next(z), flow(w), cost(c){};}p[M];void add(int x, int y, int z, int c){p[no] = point(x, y, head[x], z, c);head[x] = no++;p[no] = point(y, x, head[y], 0, -c);head[y] = no++;}void init(){memset(head, -1, sizeof(head));no = 0;}bool spfa(){ int i, x, y; queue<int>q; memset(d, 0x3f, sizeof(d)); memset(vis, false, sizeof(vis)); memset(pre, -1, sizeof(pre)); d[s] = 0; vis[s] = true; q.push(s); while(!q.empty()){ x = q.front(); q.pop(); vis[x] = false; for(i = head[x]; i != -1; i = p[i].next){ if(p[i].flow && d[y = p[i].v] > d[x] + p[i].cost){ d[y] = d[x] + p[i].cost; pre[y] = i; if(vis[y]) continue; vis[y] = true; q.push(y); } } } return d[e] != d[e + 1];}int mcmf(){ int mincost = 0, maxflow = 0, minflow, i; while(spfa()){ minflow =INF; for(i = pre[e]; i != -1; i = pre[p[i].u]) minflow = min(minflow, p[i].flow); for(i = pre[e]; i != -1; i = pre[p[i].u]){ p[i].flow -= minflow; p[i ^ 1].flow += minflow; } mincost += d[e] * minflow; maxflow += minflow; } return mincost;}};int n,m;char str[505],ss[2][505];int head[505],wr[505],id[505],dis[505],nn,b,w,tot,qz[505],iqz[505],vis[505],ans[2];//qz是图到网络流图的节点映射,iqz是逆向映射vector<pair<int,int> > temp[2],step;vector<int> seq;struct node{ int v; int next; node(int t,int n):v(t),next(n){} node(){}}edge[MAXM];void init(){ nn = 0; tot = 0; memset(head,-1,sizeof(head)); memset(id,-1,sizeof(id)); step.clear();}bool judge(int x,int la){//判断是否有奇环 bool res = true; id[x] = la; for(int i = head[x];~i;i = edge[i].next){ int v = edge[i].v; if(id[v] == -1){ res&=judge(v,la+1); if(!res) return false; } else{ if((la-id[v]+1)%2) return false; } } return res;}void dfs(int s,int c){//找错误的颜色节点 vis[s] = id[s] = 1; if(str[s]-'0'!= c) { wr[s] = 1; if(c){ w++; iqz[++tot] = s; qz[s] = tot; } else{ b++; iqz[++tot] = s; qz[s] = tot; } } for(int i = head[s];~i;i = edge[i].next){ int v = edge[i].v; if(!vis[v]){ dfs(v,c^1); } }}void bfs(int x){//计算最短距离 memset(dis,-1,sizeof(dis)); queue<int> q; q.push(x); dis[x] = 0; while(!q.empty()){ x = q.front(); int d = dis[x]; q.pop(); for(int i = head[x];~i;i = edge[i].next){ int v = edge[i].v; if(dis[v] == -1){ dis[v] = d+1; q.push(v); } } }}int findpath(int x,int to,int dep,int dis){//找最短路径 if(dep>dis) return 0; vis[x] = 1; int res = 0; if(x == to&&dep == dis){ res = 1; } for(int i = head[x];~i&&!res;i = edge[i].next){ int v = edge[i].v; if(!vis[v]){ res |= findpath(v,to,dep+1,dis); } } if(res){ seq.push_back(x); } vis[x] = 0; return res;}int main(){ //specialjudge sj; //sj.judge(); //freopen("1007.in","r",stdin); //freopen("1007.out","w",stdout); int T; int cas = 1; cin>>T; while(T--){ init(); //printf("CAS:%d\n",cas++); scanf("%d%d%s",&n,&m,str+1); for(int i = 0;i < m;i++){ int x,y; scanf("%d%d",&x,&y); edge[nn] = node(y,head[x]); head[x] = nn++; edge[nn] = node(x,head[y]); head[y] = nn++; } bool flag = true; for(int i = 1;i <= n;i++){ if(id[i] == -1){ flag = judge(i,1); if(!flag) break; } } if(!flag){ printf("-1\n"); continue; } memset(id,0,sizeof(id)); flag = true; int res = 0; for(int i = 1;i <= n;i++){//枚举所有连通块 if(!id[i]&&flag){ bool flag2 = false; for(int l = 0;l < 2;l++){ memset(wr,0,sizeof(wr)); memset(vis,0,sizeof(vis)); for(int j = 1;j <= n;j++) ss[l][j] = str[j]; temp[l].clear(); b = 0; w = 0; tot = 0; ans[l] = inf; dfs(i,l); if(w != b) { continue; } else{ flag2 = true; } MCMF::init(); MCMF::s = 0; MCMF::e = tot+1; for(int j = 1;j <= n;j++){//网络流建图 if(id[j]&&wr[j]&&str[j]-'0'==1){ MCMF::add(MCMF::s,qz[j],1,0); } if(id[j]&&wr[j]&&str[j]-'0'==0){ MCMF::add(qz[j],MCMF::e,1,0); } } for(int j = 1;j <= n;j++){ if(id[j]&&wr[j]&&str[j]-'0'==1){ bfs(j); for(int k = 1;k <= n;k++){ if(id[k]&&wr[k]&&str[k]-'0'==0){ MCMF::add(qz[j],qz[k],1,dis[k]); } } } } ans[l] = MCMF::mcmf(); for(int j = 1;j <= tot;j++){ int cc = iqz[j]; if(str[cc]-'0' == 0){//if it connect to end for(int k = MCMF::head[j];~k;k = MCMF::p[k].next){ if(MCMF::p[k].v != MCMF::e && MCMF::p[k].flow == 1){ for(int o = 0;o < 505;o++) vis[o] = 0; seq.clear(); int from,to,dis; from = iqz[MCMF::p[k].v]; to = iqz[j]; dis = -MCMF::p[k].cost; findpath(from,to,0,dis); int c = ss[l][seq[0]]-'0',pos = 0; for(int o = 0;o < 505;o++) vis[o] = 0; for(int o = 1;o < seq.size();o++){//输出操作 int tc = ss[l][seq[o]]-'0'; if(c^tc){ vis[o] = 1; int a = seq[pos],b = seq[o]; temp[l].push_back(pair<int,int>(a,b)); swap(ss[l][a],ss[l][b]); } pos = o; } for(int o = seq.size()-1;o > 0;o--){//输出操作 if(!vis[o]){ int a = seq[o],b = seq[o-1]; temp[l].push_back(pair<int,int>(a,b)); swap(ss[l][a],ss[l][b]); } } } } } } } if(!flag2){ flag = false; break; } int op; if(ans[0]<ans[1]){ op = 0; } else op = 1; res += ans[op]; for(int j = 0;j < temp[op].size();j++){ step.push_back(temp[op][j]); } for(int j = 1;j <= n;j++) str[j] = ss[op][j];//更新状态 } } if(!flag){ printf("-1\n"); continue; } printf("%d\n",res); for(int i = 0;i < step.size();i++){ printf("%d %d\n",step[i].first,step[i].second); } } return 0;}
0 0
- HDU5740 Glorious Brilliance
- 【HDU5740 2016 Multi-University Training Contest 2G】【二分图染色+费用流+路径输出】Glorious Brilliance 最少交换次数使得相邻点颜色
- 【HDU】5740 Glorious Brilliance【费用流】
- BUPT 201 Glorious Array
- hdu3854.Glorious Array
- I Still Want to Be Glorious
- 438. The Glorious Karlutka River =)
- SGU 438 -- The Glorious Karlutka River =)
- sug438 The Glorious Karlutka River =)(枚举+最大流)
- hdu 3854 Glorious Array(线段树or树状数组)
- 解题报告 之 SGU438 The Glorious Karlutka River
- SGU 438 The Glorious Karlutka River =) 动态网络流
- 【SGU438】The Glorious Karlutka River =) 分层图最大流
- sgu 438 The Glorious Karlutka River 【网络流 分层】
- Sgu 438 The Glorious Karlutka River(动态流)
- sgu 438 The Glorious Karlutka River =)(动态网络流)
- sgu 438 The Glorious Karlutka River =) 网络流 动态流
- SGU 438. The Glorious Karlutka River =) (网络流,动态流问题)
- windows 任务计划失败 返回值
- Drawable、Bitmap、byte[]之间的转换
- iOS UIWebView 的加载
- Canvas 与 双缓冲 相关文章
- vs中添加界面皮肤
- HDU5740 Glorious Brilliance
- 【redux】Action Reducer Store
- Linux入门笔记——系统目录结构
- Android Studio
- 解决ActionBar字体设置
- Activity启动另一个Activity的方式总结
- 关于javascript中=的返回值
- S5PV210——内存配置(DDR2)
- C/C++ 八大排序算法