Swap---hdu2819(最大匹配)

时间:2023-03-10 06:18:31
Swap---hdu2819(最大匹配)

题意:通过交换行或者列来实现对角线(左上角到右下角)上都是1,

首先,如果某行全是0或者某列全是0必然不满足情况输出-1,如果能转换的话,那么必然可以通过全由行(列)变换得到;

还有就是对角线上的N个1,它们各自在不同的行中出现至少一次才可以,

比如样例2中,虽然有两个1,但是它们总是处在同一列,仍然不满足要求,

很明显不能一个行对应两个列,或者说,每一行都应该有至少一个与自己对应的列才能满足条件;

那么将行作为X集合,列作为Y集合,如果map[i][j]==1,那么Xi->Yj连边,求最大匹配,这样的话没有任何一个行被两个列匹配,也就满足了我们的要求,

如果最大匹配==N,那么必然有解,否则必然无解;

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<string>
#include<stack>
#include<map>
using namespace std;
#define N 1100
#define INF 0x3f3f3f3f
#define met(a, b) memset(a, b, sizeof(a)) int used[N], G[N][N], vis[N], n; int Find(int u)
{
for(int i=; i<=n; i++)
{
if(!vis[i] && G[u][i])
{
vis[i] = ;
if(!used[i] || Find(used[i]))
{
used[i] = u;
return ;
}
}
}
return ;
} int main()
{
while(scanf("%d", &n) != EOF)
{
met(G, ); for(int i=; i<=n; i++)
{
for(int j=; j<=n; j++)
{
int op;
scanf("%d", &op);
G[i][j] = op;
}
}
int ans = ;
met(used, );
for(int i=; i<=n; i++)
{
met(vis, );
ans += Find(i);
}
if(ans < n)
{
printf("-1\n");
continue;
}
int cnt = , a[N]={}, b[N]={}; ///相当于是给一个数组used排序的过程,使得交换的次数最少;
///每次把i位置上的数,放到应该放的位置,直到当前位置是对应的数为止;
for(int i=; i<=n; i++)
{
while(i != used[i])
{
a[cnt] = i;
b[cnt] = used[i];
swap(used[i], used[used[i]]);
cnt ++;
}
} printf("%d\n", cnt);
for(int i=; i<cnt; i++)
printf("C %d %d\n", a[i], b[i]);
}
return ;
}
/*
3
0 1 1
0 0 1
1 0 0
*/