HDU 5740 - Glorious Brilliance
题意:
给出已0 1染色的无向图(不一定联通),一次操作为一对相邻点颜色互换.
问使任意相邻点颜色不同,最少需要多少次操作
分析:
交换两点的代价即为两点间最短路.
故用BFS找出所有点到任意点的最短距离,并记录路径.
对于每个连通块,按照相邻点颜色不同重新染色一遍,若发现已给的01数目与染色需要01数目不符,则不可能
不然 ,则根据已给的01数目与染色需要01数目,确定匹配的点集.
最后KM算法算出最小权值匹配即可
确定匹配后,分析下同一路上的交换顺序,确定交换步骤
不算难,就是麻烦
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=;
const int MAXM = *; int map[MAXN][MAXN];//二分图描述
int linker[MAXN],lx[MAXN],ly[MAXN];
int slack[MAXN];
int nx,ny;
bool visx[MAXN],visy[MAXN]; bool DFS(int x)
{
int y;
visx[x] = ;
for(y = ;y < ny; ++y)
{
if(visy[y]) continue;
int tmp = lx[x] + ly[y] - map[x][y];
if(tmp == )
{
visy[y] = ;
if(linker[y] == - || DFS(linker[y]))
{
linker[y] = x;
return ;
}
}
else if(slack[y] > tmp)
slack[y] = tmp;
}
return ;
}
int KM()
{
for(int i = ;i < nx; ++i) linker[i] = -,ly[i] = ;
for(int i = ;i < nx; ++i)
{
lx[i] = -INF;
for(int j = ;j < ny; ++j)
if(map[i][j] > lx[i])
lx[i] = map[i][j];
}
for(int x = ;x < nx; ++x)
{
for(int i = ;i < ny; ++i) slack[i] = INF;
while()
{
for(int i = ;i < nx; ++i) visx[i] = ;
for(int i = ;i < ny; ++i) visy[i] = ;
if(DFS(x)) break;
int d = INF;
for(int i = ;i < ny; ++i)
if(!visy[i] && d > slack[i])
d = slack[i];
for(int i = ;i < nx; ++i)
if(visx[i])
lx[i] -= d;
for(int i = ;i < ny; ++i)
if(visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
int res = ;
for(int i = ;i < ny;++i)
if(linker[i] != -)
res += map[ linker[i] ][i];
return res;
} int g[MAXN][MAXN],col[MAXN];
vector<int> X,Y,Left,Right;//X 1 Y 0
char s[MAXN];
int n,m,ans;
queue<int> p;
vector<int> G[MAXN]; bool BFS(int x,int c)//染色
{
while(!p.empty()) p.pop();
col[x] = c;
if(c) X.push_back(x);
else Y.push_back(x);
p.push(x);
int size,i;
while(!p.empty())
{
x = p.front(); p.pop();
size = G[x].size();
for(i = ; i < size; ++i)
{
if(col[ G[x][i] ] == col[x] ) return ;
else if(col[ G[x][i] ] == -)
{
col[ G[x][i] ] = col[x]^;
if( col[ G[x][i] ] ) X.push_back( G[x][i] );//1
else Y.push_back( G[x][i] );//0
p.push( G[x][i] );
}
}
}
return ;
}
vector<int> path[MAXN][MAXN];
int vis[MAXN],Pair1[MAXN],Pair2[MAXN],*Pair;
pair<int,int> Ans[MAXM];//答案 void GetPath(int u)//找到最短路并记录路径
{
int i, t, v;
for(i = ; i <= n; ++i) vis[i] = ;
while(!p.empty()) p.pop();
p.push(u);
path[u][u].push_back(u);
vis[u] = ;
g[u][u] = ;
while(!p.empty())
{
t = p.front(); p.pop();
for(i = ; i < G[t].size(); ++i)
{
v = G[t][i];
if( !vis[v] )
{
vis[v] = ;
g[u][v] = g[u][t] + ;
path[u][v] = path[u][t];
path[u][v].push_back(v);
p.push(v);
}
}
}
}
int GetSum(vector<int> &X,vector<int> &Y,int Pair[])//匹配
{
int i,j;
Left.clear(); Right.clear();
for( i = ; i < X.size(); ++i)
{
if(s[ X[i] ] == '') Left.push_back( X[i] );
}
for( i = ; i < Y.size(); ++i)
{
if(s[ Y[i] ] == '') Right.push_back( Y[i] );
}
nx = Left.size();
ny = Right.size();
for( i = ; i< nx; ++i)
{
for( j = ;j< ny; ++j)
{
int x = Left[i],y = Right[j];
map[i][j] = -g[x][y];
}
}
int sum = KM();
for(i = ; i < nx; ++i)
{
int v = Right[i] ;
int u = Left[ linker[i] ];
Pair[u] = v; Pair[v] = u;//1 0
}
return -sum;
}
void GetAns(int u,int v)
{
int i, j, k;
if(s[u] != '') swap( u, v);
vector<int> &p = path[u][v];
for(i = ; i < p.size(); i = j)
{
for(j = i; j<p.size() && s[ p[j] ] == ''; ++j); //路上第一个'1'
if(j == p.size()) break;
for(k = j; k > i; --k)
{
Ans[ans++] = make_pair(p[k], p[k - ]);
swap(s[ p[k] ],s[ p[k-] ]);
}
}
}
int solve(int st)//当前连通分支
{
int i, zero = , col0 = ;
X.clear(); Y.clear();
if(!BFS(st, )) return ;//染色
for(i = ; i < X.size(); ++i)
{
if(s[X[i]] == '') ++zero;
}
for(i = ; i < Y.size(); ++i)
{
if(s[Y[i]] == '') ++zero;
}
int sum1=INF,sum2=INF;
if(zero == Y.size() )// '0' 与 0 的数目相等,X中'0'与Y中'1'对换
{
sum1 = GetSum(X, Y, Pair1);
}
if(zero == X.size() )// '0' 与 1 的数目相等,X中'1'与Y中'0'对换
{
sum2 = GetSum(Y, X, Pair2);
}
if(sum1 == INF && sum2 == INF) return ;
if(sum1 < sum2) Pair = Pair1;
else Pair = Pair2;
for(i=;i<X.size(); ++i)
{
if(Pair[ X[i] ] != -) GetAns(X[i], Pair[ X[i] ]);
}
return ;
}
int main()
{
int i,j,t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%s", &n, &m, s+);
for(i = ; i <= n; ++i) G[i].clear();
for(i = ; i <= n; ++i)
{
for(j = ; j <= n; ++j)
{
g[i][j] = INF;
}
}
for(i = ;i <= m; ++i)
{
int x,y;
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
for(i = ; i <= n; ++i)
for(j = ; j <= n; ++j)
path[i][j].clear();
for(i = ; i <= n; ++i) GetPath(i);//最短路
for(i = ; i <= n; ++i)
{
Pair1[i] = Pair2[i] = col[i] = -;
}
bool flag=;
ans = ;
for(i = ;i <= n; ++i)//对每个连通分支
{
if(col[i]==-&&!solve(i))
{
flag = ; break;
}
}
if(!flag)
{
puts("-1"); continue;
}
printf("%d\n",ans);
for(i = ; i< ans ;++i)
printf("%d %d\n",Ans[i].first, Ans[i].second);
}
return ;
}
HDU 5740 - Glorious Brilliance的更多相关文章
- HDU5740 Glorious Brilliance【最短路 KM匹配】
HDU5740 Glorious Brilliance 题意: 给出一张不一定合法的染色图,每次可以交换相邻两点的颜色,问最少多少次能使染色图合法 合法的染色图相邻点的颜色不能相同 题解: 首先要确定 ...
- HDU 3854 Glorious Array(树状数组)
题意:给一些结点,每个结点是黑色或白色,并有一个权值.定义两个结点之间的距离为两个结点之间结点的最小权值当两个结点异色时,否则距离为无穷大.给出两种操作,一种是将某个结点改变颜色,另一个操作是询问当前 ...
- Glorious Brilliance (最短路 + 带权二分图匹配)
这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建 ...
- 2016 Multi-University Training Contest 2
8/13 2016 Multi-University Training Contest 2官方题解 数学 A Acperience(CYD)题意: 给定一个向量,求他减去一个 α(>=0)乘以 ...
- 2016 Multi-University Training Contest 2 solutions BY zimpha
Acperience 展开式子, \(\left\| W-\alpha B \right\|^2=\displaystyle\alpha^2\sum_{i=1}^{n}b_i^2-2\alpha\su ...
- HDOJ 2111. Saving HDU 贪心 结构体排序
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 【HDU 3037】Saving Beans Lucas定理模板
http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...
- hdu 4859 海岸线 Bestcoder Round 1
http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...
- HDU 4569 Special equations(取模)
Special equations Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u S ...
随机推荐
- No redirect found in host configuration file (C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet.config).
Configuration Error Description: An error occurred during the processing of a configuration file req ...
- ios属性和成员变量写在.h文件和.m文件中 区别?
1 其实是一样的.在.m文件上只能.m文件内部的才能访问的这个变量,如果在.h文件中,其他的文件也可以访问到这个变量. 2 写.h文件里边可以和其他的类进行交互,写.m里边只是在本类中使用! 3 ...
- 1218.1——OC中的常见关键字及一些基本方法
OC常见的关键字介绍: @ 看到这个关键字,我们就应该想到,这是Object-C对C语言的扩展,例如@interface XXX. @interface 声明类 @implementation 实现类 ...
- UIScrollView 代理方法
在使用UIScrollView和它的子类UITableView时,有时需要在不同操作状态下,做不同的响应. 如何截获这些状态,如正在滚动,滚动停止等,使用UIScrollViewDelegate_Pr ...
- javascript事件捕获与冒泡
对“捕获”和“冒泡”这两个概念,我想我们对冒泡更熟悉一些,因为在我们使用的所有浏览器中,都支持事件冒泡,即事件由子元素向祖先元素传播的,就 像气泡从水底向水面上浮一样.而在像firefox,chrom ...
- web项目配置webAppRootKey 获得根目录 .
log4j和web.xml配置webAppRootKey 的问题 1 在web.xml配置 <context-param> <param-name>webAppRootKey ...
- CSS3 @font-face 指定英文网页字体
@font-face是CSS3中的一个模块,他主要是把自己定义的Web字体嵌入到你的网页中,随着@font-face模块的出现,我们在Web的开发中使用字体不怕只能使用Web安全字体.可能有人要问 ...
- 利用Azure Automation实现云端自动化运维(1)
Azure Automation是Azure上的一个自动化工作流引擎,基于Powershell,来帮助用户简化,集成和自动化Azure上的运维工作,例如: 实现定时开关虚拟机,节约成本 实现定时创建删 ...
- Redhat关闭SELinux和防火墙的办法(转)
Redhat使用了SELinux来增强安全,关闭的办法为:1. 永久有效修改 /etc/selinux/config 文件中的 SELINUX="" 为 disabled ,然后重 ...
- 重大新闻:借贷宝不用绑卡了,借贷宝APP推出肖像识别新功能!
动动手指,20元人民币立即到手:http://www.cnblogs.com/mfryf/p/4754384.html 滴滴打车烧钱十几个亿,狂送打车券,很多人天天免费坐车! 去年年初百度钱包注册奖励 ...