【图论】【二分图匹配】[HDU 2819]Swap
首先可以很容易的发现一个性质:无论怎么交换行和列,每一行每一列的元素数量始终不会改变,那么就像八皇后问题一样,只不过改成了棋盘上放了n个车不能互相冲突。那么每一个1的位置代表可以放一个车,每一个0的位置代表不能放车,那么可以发现如果在当前位置可以放个车并且放了的话,那么就不能在当前车的行和列上继续放车了,那么给行和列编号把有1的位置行和列连接起来,然后就做二分图匹配,因为是在棋盘上放车那么始终不会超过n个那么只需要看最大的匹配数量是否等于n就行了,那么方案怎么输出呢。首先可以发现如果当前可行,那么棋盘上一定放置了n个车不能互相冲突,那么肯定有n个并且每一行一个,那么只需要维护一下每一行的车的列数,然后和当前的行数比较如果不一样,就和当前行(i)的第i列交换,同时维护一下下面几行的在第i列的车改成在当前这个列就行了,然后保存下先输出次数,然后输出方案。
#include <cstdio>
#include <cstring>
#include <algorithm>
//#include <conio.h>
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 400;
bool vis[MAXN+10];
int con[MAXN+10];
int endcnt;
int n, m, k, Tcnt;
struct node{
int v;
node *next;
}Edges[MAXN * MAXN * 2+10], *adj[MAXN+10], *ecnt=Edges;
void addedge(int u, int v){
++ecnt;
ecnt->v = v;
ecnt->next = adj[u];
adj[u] = ecnt;
}
bool dfs(int u){
for(node *p=adj[u];p;p=p->next){
if(!vis[p->v]){
vis[p->v] = true;
if(con[p->v]==-1 || dfs(con[p->v])){
con[u] = p->v;
con[p->v] = u;
return true;
}
}
}
return false;
}
int ys[MAXN+5];
void work(){
int ret = 0;
memset(con, -1, sizeof con);
for(int i=endcnt;i>=1;i--) if(con[i] == -1){
memset(vis, 0, sizeof vis);
ret += dfs(i);
//if(ret == n) break;
}
if(ret == n){
vector<pair<int, int> > ans;
int counter = 0;
for(int i=1;i<=endcnt;i++)
ys[i] = con[i] - n;
for(int i=1;i<=n;i++){
if(ys[i] != i){
counter++;
ans.push_back(make_pair(min(i, ys[i]), max(i, ys[i])));
for(int j=i+1; j<=n; j++){
if(ys[j] == i){
ys[j] = ys[i];
break;
}
}
}
}
printf("%d\n", counter);
for(int i=0;i<counter;i++)
printf("C %d %d\n", ans[i].first, ans[i].second);
}
else printf("-1\n");
}
bool read(){
int t1;
if(scanf("%d", &n) == EOF) return false;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d", &t1);
if(t1){
addedge(i, j+n);
addedge(j+n, i);
}
}
}
endcnt=n;
return true;
}
int main(){
while(read()){
work();
memset(adj, 0, sizeof adj);
ecnt=Edges;
}
return 0;
}
浙公网安备 33010602011771号