HDU2819 Swap 最大匹配

来源:互联网 发布:java 迭代器实现原理 编辑:程序博客网 时间:2024/05/12 13:57

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=2819

题意:

给定一个n*n的矩阵,矩阵中元素只有0和1,问能不能通过交换任意两行或任意两列的方式,使矩阵主对角线上的元素均为1,若可以,输出交换次数和交换步骤,否则输出-1,其中交换次数不能超过1000次

思路:

把矩阵的行和列看做二分图的左点集和右点集,那么就可以转化为最小点覆盖模型,容易想到若二分图的最小点覆盖(最大匹配) != n时必然无解,若有解,则通过只交换行或者只交换列都可以实现要求。从头开始扫描,用match[i]记录的信息进行交换,最终使match[i] = i (1<= i <= n)就实现了要求,记录其中的过程即可

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 110;int cas = 0;struct edge{    int to, next;}g[N*N*2];int cnt, head[N];int nx, ny, match[N];bool vis[N];int a[N][N];int res[N*10][2];void add_edge(int v, int u){    g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}bool dfs(int v){    for(int i = head[v]; i != -1; i = g[i].next)    {        int u = g[i].to;        if(! vis[u])        {            vis[u] = true;            if(match[u] == -1 || dfs(match[u]))            {                match[u] = v;                return true;            }        }    }    return false;}int hungary(){    int res = 0;    memset(match, -1, sizeof match);    for(int i = 1; i <= nx; i++)    {        memset(vis, 0, sizeof vis);        if(dfs(i)) res++;    }    return res;}int main(){    int n;    while(~ scanf("%d", &n))    {        cnt = 0;        memset(head, -1, sizeof head);        for(int i = 1; i <= n; i++)            for(int j = 1; j <= n; j++)            {                scanf("%d", &a[i][j]);                if(a[i][j] == 1) add_edge(i, j);            }        nx = ny = n;        if(hungary() != n) printf("-1\n");        else        {            int num = 0;            for(int i = 1; i <= n; i++)                if(match[i] != i) //match[i]记录的第i列匹配的行,即a[match[i]][i] = 1                { //match[i] != i,欲使match[i] = i,那么交换第i行和match[i]行                    res[num][0] = i, res[num][1] = match[i], num++;                    for(int j = 1; j <= n; j++)                        if(match[j] == i)                        {//交换第i行和match[i]行,那么原本匹配第i行的那一列的要相应变化                            swap(match[i], match[j]);                            break;                        }                }            printf("%d\n", num);            for(int i = 0; i < num; i++) printf("R %d %d\n", res[i][0], res[i][1]);        }    }    return 0;}
0 0