H - Recovery Kattis - recovery(贪心&&思路)

30 篇文章 0 订阅
6 篇文章 0 订阅

参考博客:

https://blog.csdn.net/a54665sdgf/article/details/81584632

题目链接:

https://vjudge.net/contest/265795#problem/H

题意:

给出矩阵每行每列的特点,1代表这一行或列有奇数个1,0代表这一行或列有偶数个1,让你恢复原矩阵,并且1尽可能多,如果1数量一样,要求使0尽可能靠左上角(转化成的2进制数更小)。

思路:

既然要求1尽量多,不妨初始化时全部置成1,对于全部置成1的矩阵,它对应的题目描述矩阵就是 两个全是0的串(这时需要注意,如果某行某列是奇数个1,我们也是将它看作0了,若要等价对待,需要将原川对应的值反转)。接下来两个是对两个01串的处理,在上面取一个1,下面也取一个1,将全是1的矩阵中的对应位置的1改成0,你会发现,对于新的矩阵,你所选择的01矩阵的两个1全变成0了,这是因为,一个位置的01变动,会影响两个01串对应的行和列的值。为了得到尽可能多的1,我们需要对原01串进行两两配对,而且为了得到的二进制数尽可能的少,我们需要优先将靠左的1进行配对(对应矩阵就是左上角的位置了)。

这样,如果1恰好两两配对,那么皆大欢喜。

否则,会出现两种情况:上面多1,或者下面多1

再详细点分,多出来的1可能有奇数个,也可能有偶数个

如果多出来偶数个1 ,举例来说

给出01串是:

1100

0000

这时候,如果把(1,0)位置的数变成1

串就变成

0100

1000

下一次,就可以匹配了。依次类推

需要注意的是,一定要将第一个变成0,因为要满足二进制最小的要求。

这样,变一个,再配对。需要什么条件能配成功呢?

需要有偶数个1!!!(奇数个1即是不满足条件的)

可以想象,如果给出的01串如果只有一个1,那么无论如何都得不到满足条件的矩阵,以为一个变,同时影响行和列。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 60;
int a[maxn][maxn];
string r,c;
int n,m;
bool judge()
{
    n = r.length();
    m = c.length();
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            a[i][j] = 1;
    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';
    }

    int cntrow = count(r.begin(),r.end(),'1');
    int cntcol = count(c.begin(),c.end(),'1');
    if((cntcol + cntrow)&1)
        return 0;
   
    for(int i = 0; cntrow > cntcol ; i++)
    {
        if(r[i] == '1')
        {
            r[i] = '0';
            a[i][0] = 0;
            cntrow--;
        }
    }
     for(int i = 0; cntcol > cntrow ; i++)
    {
        if(c[i] == '1')
        {
            c[i] ='0';
            a[0][i] = 0;
            cntcol--;
        }
    }
    for(int i = 0, j =0 ; i < n; i++)
    {
        if(r[i] =='1')
        {
            while(c[j]=='0')j++;
            a[i][j] = 0;
            j++;
        }
    }
    return 1;
}
int main()
{
    cin>>r>>c;
    if(judge())
    {
        for(int i = 0; i < n ; i++)
        {
            for(int j = 0; j < m; j++)
                cout<<a[i][j];
            cout<<endl;
        }
    }
    else
    {
        cout<<-1<<endl;
    }
    return 0;
}

再附上队友的代码,原理一样

#include <bits/stdc++.h>

using namespace std;
char s1[55],s2[55];
int a[55],b[55];
char s[55][55];
int main()
{
    memset(s,'1',sizeof(s));
    scanf("%s",s1);
    scanf("%s",s2);
    int cnt1=1,cnt2=1;
    char x,y;
    if(strlen(s2)&1) x='1';
    else x='0';
    if(strlen(s1)&1) y='1';
    else y='0';
    for(int i=0;s1[i]!=0;++i){
        if(s1[i]!=x) a[cnt1++]=i+1;;
    }
    for(int i=0;s2[i]!=0;++i){
        if(s2[i]!=y) b[cnt2++]=i+1;
    }
    int cnt=cnt1+cnt2;
    if(cnt&1){
        printf("-1\n");
        return 0;
    }
    while(cnt1<cnt2) a[cnt1++]=1;
    while(cnt2<cnt1) b[cnt2++]=1;
    sort(a+1,a+cnt1);sort(b+1,b+cnt2);
    for(int i=1;i<cnt1;++i){
        s[a[i]][b[i]]='0';
    }
    for(int i=1;i<=strlen(s1);++i){
        for(int j=1;j<=strlen(s2);++j){
            printf("%c",s[i][j]);
        }
        putchar('\n');
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值