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 ...
随机推荐
- ios10 适配问题总结
看各个大神整理而成 1.检查版本问题 不可以像下面这样用 #define isiOS10 ([[[[UIDevice currentDevice] systemVersion] substringTo ...
- hdu1219
Problem Description Ignatius is doing his homework now. The teacher gives him some articles and asks ...
- Emacs下编译C++/C程序<转>
1.启动Emacs,在终端输入“emacs&”命令后回车(你也可以输入“emacs”命令,不过当你在使用Emacs的时候,当前终端 就不为你工作了:并且如果你熟练使用Emacs的话也可以输入“ ...
- 禁用物料不允许BOM
应用 Oracle Bill Of Materiel 层 Level Function 函数名 Funcgtion Name BOM_BOMFDBOM 表单名 Form Name BOMFDBOM ...
- grok 正则也支持常规正则
2016-08-29 17:40:01,19 INFO com.zjzc.common.utils.HttpUtil - 请求接口: https://www.zjcap.cn/pay/interfac ...
- 安装开源项目 MultiType (基于 RecyclerView)出现的各种问题 -- 自己的第一篇博客
一.引入开源项目的方式 使用开源项目 MultiType 的两种方式: 1.maven引入:在主Module 的 build.gradle 中加入 dependencies { ...... comp ...
- UESTC_Judgment Day CDOJ 11
Today is the judgment day. The world is ending and all man will pay for their guilt and sin. Now the ...
- Longest Substring Without Repeating Characters 解答
Question Given a string, find the length of the longest substring without repeating characters. For ...
- 有序线性搜索(Sorted/Ordered Linear Search)
如果数组元素已经排过序(升序),那我们搜索某个元素就不必遍历整个数组了.在下面给出的算法代码中,到任何一点,假设当前的arr[i]值大于搜索的值data,就可以停止搜索了. #include<s ...
- OpenWrt backfire trunk源码下载及编译
OpenWrt signature check failed remove wrong signature file svn co svn://svn.openwrt.org/openwrt/bran ...