Glorious Brilliance (最短路 + 带权二分图匹配)
这是一道代码大题。一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!!
把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建图,利用二分图KM算法去匹配最优方案。然后求出每一组更换的,利用原先已经求好的路径去储存答案。
#include<bits/stdc++.h>
using namespace std; const int inf = 0x3f3f3f3f;
const int maxn = 5e2 + ;
vector<pair<int, int> >ANS;
vector<int>Gra[maxn], path[maxn][maxn], X, Y, Left, Right;
char str[maxn];
int g[maxn][maxn], col[maxn], *pairr, pairr1[maxn], pairr2[maxn];
int mp[maxn][maxn], lx[maxn], ly[maxn], linker[maxn], slack[maxn];
int n, m, l, nx, ny;
bool vis[maxn], visx[maxn], visy[maxn]; bool DFS(int x){
visx[x] = true;
for(int y = ; y < ny; y++) {
if(visy[y])
continue;
int tmp = lx[x] + ly[y] - mp[x][y];
if(tmp == ) {
visy[y] = true;
if(linker[y] == - || DFS(linker[y])) {
linker[y] = x;
return true;
}
} else if(slack[y] > tmp)
slack[y] = tmp;
}
return false;
} int KM(){
memset(linker,-,sizeof(linker));
memset(ly,,sizeof(ly));
for(int i = ; i < nx; i++) {
lx[i] = -inf;
for(int j = ; j < ny; j++)
if(mp[i][j] > lx[i])
lx[i] = mp[i][j];
}
for(int x = ; x < nx; x++) {
for(int i = ; i < ny; i++)
slack[i] = inf;
while(true) {
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
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 -= mp[linker[i]][i];
return res;
} void getMinRoad(int u){
queue<int>que;while(!que.empty())que.pop();
que.push(u);g[u][u] = ;
path[u][u].push_back(u);
memset(vis, false, sizeof(vis));
vis[u] = true; while(!que.empty()){
int st = que.front();que.pop(); for(auto to : Gra[st]){
if(vis[to]) continue;
vis[to] = true;
g[u][to] = g[u][st] + ;
path[u][to] = path[u][st];
path[u][to].push_back(to);
que.push(to);
}
}
} bool color(int st){
queue<int> que;while(!que.empty())que.pop();
X.push_back(st);
que.push(st);
col[st] = ;
while(!que.empty()){
int u = que.front();que.pop(); for(auto v : Gra[u]){
if(col[v] == col[u]) return false;
if(col[v] != -) continue;
col[v] = col[u] ^ ;
if(col[v]) Y.push_back(v);
else X.push_back(v); que.push(v);
}
}
return true;
} void GetAns(int u, int v, int setp){
if(u == v) return ;
vector<int>&tmp = path[u][v];
for(int i = ; i < tmp.size() - ; i ++)
if(str[tmp[i]] != str[tmp[i +]]){
ANS.push_back(make_pair(tmp[i], tmp[i + ]));
swap(str[tmp[i]], str[tmp[i + ]]);
GetAns(u, tmp[i], setp + );
GetAns(tmp[i + ], v, setp + );
return ;
}
} int getSum(vector<int>A, vector<int>B, int Pair[]){
Left.clear(); Right.clear();
for(auto x : A) if(str[x] == '') Left.push_back(x);
for(auto x : B) if(str[x] == '') Right.push_back(x); nx = ny = Left.size();
for(int i = ; i < nx; i ++)
for(int j = ; j < ny; j ++)
mp[i][j] = - g[Left[i]][Right[j]];
int ret = KM(); for(int i = ; i < nx; i ++){
int u = Right[i], v = Left[linker[i]];
Pair[u] = v;Pair[v] = u;
}
return ret;
} bool solve(int st){
int zero = , sum1 = inf, sum2 = inf;
X.clear(), Y.clear();
if(!color(st)) return ;
for(auto x : X) if(str[x] == '') zero ++;
for(auto x : Y) if(str[x] == '') zero ++; if(zero == X.size()) sum1 = getSum(X, Y, pairr1);
if(zero == Y.size()) sum2 = getSum(Y, X, pairr2); if(sum1 == inf && sum2 == inf) return false;
pairr = sum1 > sum2 ? pairr2 : pairr1;
for(auto x : X) if(pairr[x] != -) GetAns(x, pairr[x], ); return true;
} void init(){
memset(pairr1, -, sizeof(pairr1));
memset(pairr2, -, sizeof(pairr2));
memset(slack, , sizeof(slack));
for(int i = ; i <= n; i ++){
Gra[i].clear();
col[i] = -;
for(int j = ; j <= n; j ++){
g[i][j] = inf;
path[i][j].clear();
}
}
ANS.clear();
} int main(){
int T,a,b;scanf("%d",&T);
while(T --){
scanf("%d%d%s", &n, &m, str + );
init();
for(int i = ; i < m; i ++){
scanf("%d%d",&a,&b);
Gra[a].push_back(b);
Gra[b].push_back(a);
}
for(int i = ; i <= n; i ++) getMinRoad(i); bool flag = true;
for(int i = ; i <= n; i ++){
if(col[i] == - && !solve(i)){
flag = false;break;
}
}
if(!flag){
printf("-1\n");
continue;
}
printf("%d\n", ANS.size());
for(int i = ; i < ANS.size(); i ++){
printf("%d %d\n",ANS[i].first, ANS[i].second);
}
}
return ;
}
Glorious Brilliance (最短路 + 带权二分图匹配)的更多相关文章
- POJ 2195 Going Home (带权二分图匹配)
POJ 2195 Going Home (带权二分图匹配) Description On a grid map there are n little men and n houses. In each ...
- 运动员最佳匹配问题 KM算法:带权二分图匹配
题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...
- 费用流模板(带权二分图匹配)——hdu1533
/* 带权二分图匹配 用费用流求,增加源点s 和 汇点t */ #include<bits/stdc++.h> using namespace std; #define maxn 1000 ...
- POJ 2195 Going Home | 带权二分图匹配
给个地图有人和房子 保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价 问让人都住在房子里最小代价 显然是个带权二分图最大匹配 转化成以一个网络,规定w是容量,c是代价 1.S向人连边,w=1 ...
- hdu5045:带权二分图匹配
题目大意 : n个人 做m道题,其中 每连续的n道必须由不同的人做 已知第i人做出第j题的概率为pij,求最大期望 思路:考虑每连续的n道题 都要n个人来做,显然想到了带权的二分图匹配 然后就是套模板 ...
- [NOI2012]美食节——费用流(带权二分图匹配)+动态加边
题目描述 小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜品.当所有的同学点餐结束后,菜品的制作任务就会分配给每个厨师.然后每个厨师就会同时开始 ...
- [HAOI2008]移动玩具(状压&带权二分图)
题目描述 • 一个 4 × 4 的 0/1 矩阵 • 每次可以交换相邻两个元素 • 求从初始状态到目标状态的最小交换次数 输入格式 前四行,每行一个长为 4 的 0/1 字符串,描述初始状态. 后四行 ...
- Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)
Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配) Description 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的 ...
- KM(Kuhn-Munkres)算法求带权二分图的最佳匹配
KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后, ...
随机推荐
- Java之旅_高级教程_URL处理
摘自 :http://www.runoob.com/java/java-url-processing.html Java URL 处理 URL(Uniform Resource Locator)中文名 ...
- js数组方法汇总
下面主要汇总一下数组的方法 数组方法: 1.检测是否为数组的方法:Array.isArrray(); var arr=[1,2,3,4,5]; var str='string'; console.lo ...
- kali蓝牙连接
http://blog.csdn.net/hailangnet/article/details/47723181 http://www.aiuxian.com/article/p-3012084.ht ...
- 爬虫请求库——selenium
selenium模块 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题.selenium的缺点是效率会变得很慢. sel ...
- javascript篇-console.log()打印object却显示为字符串[object object]
console.log打印对象遇到的一个问题,如下截图 打印结果与预期不符,原因是因为字符串‘a’和对象object拼接在一起,拼成了一个字符串
- Ubuntu Server16.04 配置网卡
展示全部启动网卡 $ ifconfig 配置网卡 $ sudo vi /etc/network/interfaces auto enp2s0 iface enp2s0 inet static addr ...
- Python 全栈开发三 python基础 条件与循环
一. 条件语句 python条件语句是根据一条或多条语句的执行结果的真假(True Or False)来决定代码块的执行. 而执行内容可以多行,以缩进来区分表示同一范围. 1.Python判断条件真假 ...
- DLNg序列模型第二周NLP与词嵌入
1.使用词嵌入 给了一个命名实体识别的例子,如果两句分别是“orange farmer”和“apple farmer”,由于两种都是比较常见的,那么可以判断主语为人名. 但是如果是榴莲种植员可能就无法 ...
- windows下使用pyinstaller把python文件打包成exe可执行文件
使用pyinstaller打包有个好处就是所有依赖都打包进去了,可以随意把文件移动到别的电脑上使用 安装 pip install pyinstaller 新建一个demo.py文件 #!/usr/bi ...
- 我的Chrome插件
1.AdBlock 用来屏蔽广告,用过的人都说好. 2.Flash Block(Plus) 用来限制Flash的播放. 3.Flash Control 用来限制Flash的播放. 4.Full Pag ...