【HDOJ 5375】 Gray code

【HDOJ 5375】 Gray code

做这题首先要明白gary code(格雷码)的算法
假设有二进制 10010 对应的格雷码就是它本身与它左移一位后的二进制异或

10010
  10010
11011

题目中每个位置都给了一个价值a 给的二进制由‘0’ ‘1’ ‘?’组成 ‘?’可以是1也可是0 格雷码为1的位置所对应的价值加和为最终价值 输出最大的最终价值

根据二进制转换格雷码的方法可知 当前位置与前一位置异或结果为当前位置格雷码

推理可知连续的’?’对结果起决定作用 可知有如下几种情况
‘0’ 奇数个’?’ ‘1’
‘1’ 奇数个’?’ ‘0’
0 奇数 0
1 奇数 1
0 偶数 1
1 偶数 0
0 偶数 0
1 偶数 1
而进一步研究可知
1 偶数 0
0 偶数 1
0 奇数 0
1 奇数 1
一定有让所有’?’下价值算入的情况
其余一定要去掉一个数 当然选其间的最小价值

另外有两个特例 如果????连续到右时 无论奇偶期间价值均可选
开头为?时 该段’?’左端其实为’0’(界外 但计算格雷码时要与第一位异或)

总结上面的情况即可写出

代码如下:

#include <iostream>
#include  <cstdio>
#include <cstdlib>
#include <cstring>
#define INF 0x3f3f3f3f

using namespace std;

char str[233333];
int a[233333];

int main()
{
    int t,n,i,len,mm,z = 0,sum;
    char l;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",str);
        n = strlen(str);
        sum = len = 0;
        l = '0';
        mm = INF;
        for(i = 0; i < n; ++i)
        {
            scanf("%d",&a[i]);
            sum += a[i];
            mm = min(mm,a[i]);
            if(str[i] == '?')
            {
                len++;
            }
            else
            {
                if(len%2)
                {
                    if(l != str[i]) sum -= mm;
                }
                else
                {
                    if(l == str[i]) sum -= mm;
                }
                len = 0;
                mm = INF;
                l = str[i];
            }
        }
        printf("Case #%d: %d\n",++z,sum);
    }
    return 0;
}

刚刚逛大牛们的博客时发现这题用dp也可以 并且更好理解
列个if大家就明白了

scanf("%d",&a);
dp[0][0] = 0;
if(str[0] != '0') dp[0][1] = a;//初始化最左端价值
for(i = 1; str[i]; ++i)
{
    scanf("%d",&a);
    if(str[i] == '0')
    {
        if(str[i-1] == '0') dp[i][0] = dp[i-1][0];
        else if(str[i-1] == '1') dp[i][0] = dp[i-1][1] + a;
        else if(str[i-1] == '?') dp[i][0] = max(dp[i-1][0],dp[i-1][1]+a);
    }
    else if(str[i] == '1'){同上}
    else if(str[i] == '?')
    {
        if(str[i-1] == '0') 
        {
            dp[i][0] = dp[i-1][0];
            dp[i][1] = dp[i-1][0]+a;
        }
        else if(str[i-1] == '1') 
        {
            dp[i][0] = dp[i-1][1] + a;
            dp[i][1] = dp[i-1][1];
        }
        else if(str[i-1] == '?') 
        {
            dp[i][0] = max(dp[i-1][0],dp[i-1][1]+a);
            dp[i][1] = max(dp[i-1][1],dp[i-1][0]+a);
        }
    }
}

上代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

char str[233333];
int dp[233333][2];

int main()
{
    int t,k = 0,i,a;

    scanf("%d",&t);
    while(++k,t--)
    {
        scanf("%s",str);

        scanf("%d",&a);
        dp[0][0] = dp[0][1] = 0;
        if(str[0]-'0') dp[0][1] = a;


        for(i = 1; str[i]; ++i)
        {
            scanf("%d",&a);
            if(str[i] != '?')
            {
                if(str[i-1] == '?')
                {
                    dp[i][str[i]-'0'] = max(dp[i-1][str[i]-'0'],dp[i-1][(str[i]-'0'+1)%2]+a);
                }
                else dp[i][str[i]-'0'] = dp[i-1][str[i-1]-'0'] + ((str[i] == str[i-1])? 0: a);
            }
            else//1跟0的我给写一块。。发现跟分开写代码量差不多。。分开写还好理解点……
            {
                if(str[i-1] == '?')
                {
                    dp[i][0] = max(dp[i-1][0],dp[i-1][1]+a);
                    dp[i][1] = max(dp[i-1][1],dp[i-1][0]+a);
                }
                else
                {
                    dp[i][0] = dp[i-1][str[i-1]-'0'] +((str[i-1]-'0')? a: 0);
                    dp[i][1] = dp[i-1][str[i-1]-'0'] + ((str[i-1]-'0')? 0: a);
                }
            }
        }
        if(str[i-1]!='?') printf("Case #%d: %d\n",k,dp[i-1][str[i-1]-'0']);
        else printf("Case #%d: %d\n",k,max(dp[i-1][0],dp[i-1][1]));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值