题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2819
题目大意:
给定N * N矩阵,每个条目等于0或1.您可以交换任意两行或任意两列。你能找到一种让所有对角线条目等于1的方法吗?
输入中有几个测试用例。每个测试用例的第一行是整数N(1 <= N <= 100)。然后是N行,每行包含N个数字(0或1),按空格分隔,表示N * N矩阵。
对于每个测试用例,第一行包含交换数M.然后M行跟随,其格式为“R ab”或“C ab”,表示交换行a和行b,或交换列a和列b 。(1 <= a,b <= N)。任何正确答案都将被接受,但是M应该大于1000.
如果不可能使所有对角线条目等于1,则只输出一个包含“-1”的条目。
样本输入
2
0 1
1 0
2
1 0
1 0
样本输出
1
R 1 2
-1
思路:用行与列匹配。如果它可以做到,那么只交换行或者只交换列就可以了。
如果只交换行的话。对于第i行,只考虑第i列,是否存在1,假如:mp[j][i],建图:e[i][j]=1。
然后就是求最大匹配。如果zdl=n,那么就可以。
就是求方案,这零,如果1和2匹配,那么后面有与2匹配,在1和2交换后,现在就是与1匹配了。这点要处理一下。
#include <bits/stdc++.h>
using namespace std;
int n,m;//顶点数n和边的数目m
int e[110][110];//保存一个无向图
int book[110];//每次都标记那个去了和那个没去
int match[110];//标记匹配
int dfs (int u)
{
int i;
for (i=1;i<=n;i++)
{
if (book[i]==0&&e[u][i]==1)//这个点在同一次上没去过,而且他们能联通
{
book[i]=1;//这个点已经尝试过了
if (match[i]==0||dfs(match[i]))//这个点还没有被匹配,
//或者,他可以匹配其他的人
{
//他们就能够匹配
match[i]=u;//判断哪个,就是修改那个
//match[u]=i;不用的,错误的
return 1;
}
}
}
return 0;
}
int work()
{
memset(match, 0, sizeof(match));
int i_count=0;
for (int i=1;i<=n;i++)//尝试遍历每一个顶点
{
memset (book,0,sizeof(book));
if (dfs(i))
{
i_count++;//若能找到新的匹配,就++
}
}
return i_count;
}
int L[10010], R[10010], cut=0;
int main ()
{
while(~scanf ("%d",&n))
{
memset(e, 0, sizeof(e));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&e[i][j]);
}
}
int ans=work();
if(ans!=n)
{
printf("-1\n");
}
else
{
cut=0;
for(int i=1;i<=n;i++)
{
//cout<<"::::"<<match[i]<<endl;
if(match[i]==i)
{
continue;
}
cut++;
L[cut]=i;
R[cut]=match[i];
for(int j=1;j<=n;j++)//当第i行与第match[i]行交换时,所有与i
//行交换的都相当与match[i]行交换。
{
if(match[j]==i)
{
swap(match[i], match[j]);
}
}
}
printf("%d\n",cut);
for(int i=1;i<=cut;i++)
{
printf("R %d %d\n",L[i], R[i]);
}
}
}
return 0;
}
/* 3 0 1 0 0 0 1 1 0 0 */