题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1059
题意:给定一个 n×n 的01矩阵,可以任意交换两行或两列的数字,问是否能调整出一个局面,使得矩阵的主对角线(左上角到右下角的连线)上都是1。 n≤200 。
题解:
由于每次可以变化一些元素为1的点的行号与列号,但是其相对位置是不变的,也就是说对于
(i,j)
的元素,经过变换之后是
(ai,bj)
,
{an}
和
{bn}
是
1∼n
的排列,所以我们可以抛弃这些点的行号与列号来分析他们的相对关系。
目标局面是
(i,i)
的元素为1,即存在
n
个元素为1的点使得对于每个点
题目转化为二分图匹配,每一行匹配一列,均能成功匹配则存在调整方案,时间复杂度
O(n3)
。
代码:
#include <cstdio>
#include <cstring>
const int maxn = 201;
int n, mark[maxn];
bool vis[maxn][maxn], y[maxn];
bool find(int x)
{
for(int i = 1; i <= n; ++i)
if(vis[x][i] && !y[i])
{
y[i] = 1;
if(!mark[i] || find(mark[i]))
{
mark[i] = x;
return 1;
}
}
return 0;
}
bool check()
{
for(int i = 1; i <= n; ++i)
{
memset(y, 0, sizeof y);
if(!find(i)) return 0;
}
return 1;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(vis, 0, sizeof vis);
memset(mark, 0, sizeof mark);
scanf("%d", &n);
for(int i = 1, x; i <= n; ++i)
for(int j = 1; j <= n; ++j)
{
scanf("%d", &x);
if(x) vis[i][j] = 1;
}
puts(check() ? "Yes" : "No");
}
return 0;
}