2018北美邀请赛 H. Recovery (贪心)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a54665sdgf/article/details/81584632

题目大意:告诉你一个矩阵每一行和每一列的元素和的奇偶性,让你找出一个满足要求的矩阵,要求矩阵上每个位置的数均为0或1,而且1的数量要尽可能多。并且在此基础上,矩阵的字典序要尽可能小。

样例输入1

0110
1001

样例输出1

1111
0111
1110
1111

样例输入2

0
1

样例输出2

-1

样例输入3

11
0110

样例输出3

1011
1101

这道题让我回想起了以前做过的UVA - 11082,两者的题意非常相近,唯一的区别就是把矩阵每行每列的和换成了异或和,于是就不由自主地想用网络流的方法做,把自己的思路带偏了......

其实这道题用贪心的方法就能过。

首先我们发现,改变矩阵的一个元素,导致的结果必然是它所对应的行和列的奇偶性同时发生变化。

于是我们可以先把矩阵的所有位置都填上1,然后算出有哪些行和列的奇偶性需要发生改变,再将相应的位置变为0即可。则问题转化成了:给你两个01串,你每次都能从两个串中各挑一个位置将这个位置上的0或1反转,让你用尽可能少的操作,把两个串的所有位置都变成0。

不难发现,当两个串中1的个数为奇数的时候,问题是无解的,因为你的操作不会改变1的个数的奇偶性。

考虑1的个数为偶数的情况:

1.当两个串中的1的个数相等时,可以按照它们所在行和列的下标两两配对。

2.当两个串中1的个数不相等时,可以先把行或列所对应的串中多余的1与下标最小的列或行进行配对,然后剩下的按照1中的方法处理。

注意为了使得操作后产生的字典序最小,每次操作总是要尽可能选择下标小的行和列进行配对。(贪心思想)

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
#define FRER() freopen("i.txt","r",stdin)
#define FREW() freopen("o.txt","w",stdout)

using namespace std;
typedef long long LL;
const int N=50+10;
int a[N][N],n,m;
string r,c;

bool solve()
{
    n=r.length(),m=c.length();

    //将矩阵中的所有元素初始化为1
    for(int i=0; i<n; ++i)
        for(int j=0; j<m; ++j)
            a[i][j]=1;

    //算出需要改奇偶性的行和列,1代表需要改变。如果行或者列为奇数,则需要反转1和0
    if(m&1)
    {
        for(int i=0; i<n; ++i)
            r[i]=r[i]=='0'?'1':'0';
    }
    if(n&1)
    {
        for(int i=0; i<m; ++i)
            c[i]=c[i]=='0'?'1':'0';
    }

    //统计r和c中1的个数,如果和为奇数则无解
    int cntr=count(r.begin(),r.end(),'1');
    int cntc=count(c.begin(),c.end(),'1');
    if((cntr+cntc)&1)return false;

    //将行或者列中多余的1与第一列或者第一行配对
    for(int i=0; cntr>cntc; ++i)
    {
        if(r[i]=='1')
        {
            r[i]='0';
            a[i][0]=0;
            cntr--;
        }
    }
    for(int i=0; cntc>cntr; ++i)
    {
        if(c[i]=='1')
        {
            c[i]='0';
            a[0][i]=0;
            cntc--;
        }
    }

    //剩下的行和列一一配对
    for(int i=0,j=0; i<n; ++i)
    {
        if(r[i]=='1')
        {
            while(c[j]=='0')++j;
            a[i][j]=0;
            ++j;
        }
    }
    return true;
}

int main()
{
    //FRER();
    cin>>r>>c;
    if(solve())
    {
        for(int i=0; i<n; ++i)
        {
            for(int j=0; j<m; ++j)
                printf("%d",a[i][j]);
            printf("\n");
        }
    }
    else
    {
        printf("-1\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/81584632