题意:

    给出已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的更多相关文章

  1. HDU5740 Glorious Brilliance【最短路 KM匹配】

    HDU5740 Glorious Brilliance 题意: 给出一张不一定合法的染色图,每次可以交换相邻两点的颜色,问最少多少次能使染色图合法 合法的染色图相邻点的颜色不能相同 题解: 首先要确定 ...

  2. HDU 3854 Glorious Array(树状数组)

    题意:给一些结点,每个结点是黑色或白色,并有一个权值.定义两个结点之间的距离为两个结点之间结点的最小权值当两个结点异色时,否则距离为无穷大.给出两种操作,一种是将某个结点改变颜色,另一个操作是询问当前 ...

  3. Glorious Brilliance (最短路 + 带权二分图匹配)

    这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建 ...

  4. 2016 Multi-University Training Contest 2

    8/13 2016 Multi-University Training Contest 2官方题解 数学 A Acperience(CYD)题意: 给定一个向量,求他减去一个  α(>=0)乘以 ...

  5. 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 ...

  6. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  7. 【HDU 3037】Saving Beans Lucas定理模板

    http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...

  8. hdu 4859 海岸线 Bestcoder Round 1

    http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...

  9. HDU 4569 Special equations(取模)

    Special equations Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u S ...

随机推荐

  1. PHP学习笔记三十五【Try】

    <?php function AddUser($name) { if($name=="张三") { echo "add success"; return ...

  2. 我跟着siki学Unity3D游戏开发——PongGame

    一.屏幕坐标转换为世界坐标. 1.游戏逻辑,根据界面布局,将墙体控制到对应的位置: vector3 position=Camer.main.ScreenToWorldPoint(new vetor2( ...

  3. mysql截取字符串

    mysql 字符串截取1.从左开始截取字符串left(str,length)被截取字段,截取长度select left('admin1213',5) from table 2.从右开始截取字符串rig ...

  4. javascript统计输入文本的简易方法

    计算文本框的输入字符数的简易方法: ]; var tValue = text.value; num = Math.ceil(getLength(tValue)/); //正则:用于区分中文为两个字节 ...

  5. shell之变量替换:临时替换

    ​${FILE:-word} 若变量为空,给变量FILE添加一个临时默认值word,FILE本身值并不变化eg: FILE1=${FILE:-word} 若FILE为空,则赋予FILE1值word $ ...

  6. SQL Server 索引重建的 4 种方法

    解决方法 方法 1. 重建指定索引,这种方法没有性能可谈.重建时表还不可访问. 方法 2. 在线重建索引,只有SQL Server 企业版才支持. 方法 3. 使用填充因子重建,这样做不一定可以减小查 ...

  7. TD数量不确定时如何让其宽度平均分布

    D数量不确定时如何让其宽度平均分布?答案很简单,我们只要在table里面加上一下代码就可以实现. table { width: 100%; table-layout: fixed; }

  8. Keil C -WARNING L15: MULTIPLE CALL TO SEGMENT

    1.第一种错误信息 ***WARNING L15: MULTIPLE CALL TO SEGMENT SEGMENT: ?PR?_WRITE_GMVLX1_REG?D_GMVLX1 CALLER1: ...

  9. < IOS > IOS适配,简单的分析解决一下

    版权:张英堂 欢迎转载,转载请注明出处. 做的项目很多,一到适配的时候头就大了,IOS6,7的适配,屏幕的适配,当然还有下一步要出4.7屏幕,也要做适配....悲剧的移动端的人员. 怎么做一个通用的适 ...

  10. Python-memcached的基本使用 - Flynewton成长点滴 - 开源中国社区

    Python-memcached的基本使用 - Flynewton成长点滴 - 开源中国社区 Python-memcached的基本使用 发表于3年前(2010-12-04 00:02)   阅读(9 ...