HDU2819【二分匹配与矩阵的秩】

题意:

给出一个矩阵问能否实现对角线全部是1,能的话输出路径,不能的话输出-1

思路:

首先根据矩阵的性质,这一定是一个满秩矩阵,所以只根据行或列交换就一定能实现。

所以行和列构成二分图,然后跑一发匈牙利就知道行不行。

然后怎么输出交换的步骤呢,我们只考虑列交换的话,在对于数组cy[ ]也就是存列的配对对象的数组,对于每个列可以寻找哪个列配对的行是等于他的,因为对角线上行等于列。

如果等于他,而且这个列就是本身他的列,那么这样就好了,如果不是的话就要交换,达到目的,那么还要处理,因为一旦交换他们配对的行就变了。

#include<bits/stdc++.h>
using namespace::std;
typedef pair<int,int> PII;

const int N = 1e2+10;

PII swp[1010];
bool rel[N][N];
bool vis[N];
int cy[N],cx[N];
int n;

bool FindPath(int u)
{
    for(int v=1;v<=n;v++)
    {
        if(vis[v]) continue;
        if(rel[u][v])
        {
            vis[v]=1;
            if(cy[v]==-1||FindPath(cy[v]))
            {
                cx[u]=v;
                cy[v]=u;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&rel[i][j]);

        int ans=0;
        memset(cx,-1,sizeof(cx));
        memset(cy,-1,sizeof(cy));
        for(int i=1;i<=n;i++)
        {
            if(cx[i]==-1){
            memset(vis,0,sizeof(vis));
            if(FindPath(i))
                ans++;
            }
        }
        if(ans==n)
        {
            int num=0;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    if(cy[j]==i)
                    {
                        if(i!=j)
                        {
                            swp[num].first=i;swp[num].second=j;
                            swap(cy[i],cy[j]);
                            num++;
                        }
                        break;
                    }
                }
            }
            printf("%d
",num);
            for(int i=0;i<num;i++)
                printf("C %d %d
",swp[i].first,swp[i].second);
        }
        else
            puts("-1");
    }
    return 0;
}




原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777456.html