HDU 2819 Swap 【二分图匹配 交换方法】

Description

Given an N*N matrix with each entry equal to 0 or 1. You can swap any two rows or any two columns. Can you find a way to make all the diagonal entries equal to 1?

Input

There are several test cases in the input. The first line of each test case is an integer N (1 <= N <= 100). Then N lines follow, each contains N numbers (0 or 1), separating by space, indicating the N*N matrix.

Output

For each test case, the first line contain the number of swaps M. Then M lines follow, whose format is “R a b” or “C a b”, indicating swapping the row a and row b, or swapping the column a and column b. (1 <= a, b <= N). Any correct answer will be accepted, but M should be more than 1000.

If it is impossible to make all the diagonal entries equal to 1, output only one one containing “-1”.

Sample Input

2
0 1
1 0
2
1 0
1 0

Sample Output

1
R 1 2
-1

题意:给出一个01矩阵,每次交换某两行或者某两列,使得最终矩阵对角线全是1,问是否可行,可行输出交换次数及方法

做法:1A好开心~~~~

这种nxn矩阵神马的很容易想到是让行作为左边,列作为右边,位置是1的连边,如果是最大匹配数是n那么可解。问题是如何交换?根据增广路的思想,我们尽量去满足匹配的要求(说是增广路有点牵强啊==)由于跑匈牙利的时候是linker[y]=x那么当我们发现有一组的linker[i]!=i时就要交换swap(linker[i],linker[linker[i]]);一直递归下去就完事了

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define M 550
    #define MAXN 100
    #define inf 0x3f3f3f3f
    int uN,vN;//u,v数目
    int g[MAXN][MAXN];
    int linker[MAXN];
    bool used[MAXN];
    bool dfs(int u)//从左边开始找增广路径
    {
        int v;
        for(v=0;v<vN;v++)//这个顶点编号从0开始,若要从1开始需要修改
          if(g[u][v]&&!used[v])
          {
              used[v]=true;
              if(linker[v]==-1||dfs(linker[v]))
              {//找增广路,反向
                  linker[v]=u;
                  return true;
              }
          }
        return false;//这个不要忘了,经常忘记这句
    }
    int hungary()
    {
       // puts("hungary");
        int res=0;
        int u;
        memset(linker,-1,sizeof(linker));
        for(u=0;u<uN;u++)
        {
            memset(used,0,sizeof(used));
            if(dfs(u)) res++;
        }
        return res;
    }
    int t,m,n,tot;
    vector< pair<int,int> >ans;
    void dfs2(int x)
    {
        ans.push_back(make_pair(linker[x]+1,linker[linker[x]]+1));
      //  printf("R %d %d\n",,);
        tot++;
        swap(linker[x],linker[linker[x]]);
        bool exi=0;
        for(int i=0;i<n;i++)
        {
            if(linker[i]!=i)
            {
                dfs2(i);
                exi=1;
                break;
            }
        }
        return;
    }
    int main()
    {
       // freopen("cin.txt","r",stdin);
        while(~scanf("%d",&n))
        {
            uN=n;
            vN=n;
            memset(g,0,sizeof(g));
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                {
                    int x;
                    scanf("%d",&x);
                    if(x==1)g[i][j]=1;
                }
            }
            if(hungary()!=n)puts("-1");
            else
            {
                tot=0;
                ans.clear();
                for(int i=0;i<n;i++)
                {
                    if(linker[i]!=i)
                    {
                        dfs2(i);
                        break;
                    }
                }
                printf("%d\n",tot);
                for(int i=0;i<ans.size();i++)
                    printf("R %d %d\n",ans[i].first,ans[i].second);
            }
        }
        return 0;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值