训练赛6(2014上海全国邀请赛——题目重现 )

本文回顾了2014年上海全国邀请赛中的三道题目:A-HDU5090的动态规划解决策略,C-HDU5092的二维DP路径搜索,以及J-HDU5099字符串比较算法。通过实例解析展示了如何运用思维和特定算法技巧来解决这些计算机科学问题。
摘要由CSDN通过智能技术生成

训练赛6(2014上海全国邀请赛——题目重现 )

导语

区域赛邀请赛练习,知道自己菜,所以挑一些看起来能做的做一做,整理一下

涉及的知识点

思维、dp

链接:2014上海全国邀请赛——题目重现

题目

A(HDU 5090)

题目大意:有N个盒子,每个盒子有初始球的数量,给出一个数字K,对每个盒子可以额外添加K个球或者不加球,进行多次操作后,如果最后能使得将盒子按照球数量升序排序,并且第i个盒子对应的个数就是i,则Jerry胜利,反之Tom胜利,判断谁胜利,多组样例

思路:开一个桶记录每个数字出现的个数,然后遍历1~N的桶,如果某个值为空,就回溯,看看该值-t*K是否存在多的个数,存在,则说明当前值可以被转换,不存在,则代表该值无法得到

代码

#include <bits/stdc++.h>
using namespace std;
int K,N,bucket[121],M;//开桶
int main() {
    scanf("%d",&M);
    while(M--) {
        bool flag=0;
        scanf("%d%d",&N,&K);
        for(int i=0; i<N; i++) {
            int t;
            scanf("%d",&t);
            bucket[t]++;
        }
        for(int i=1; i<=N; i++) {
            if(bucket[i]==0) {
                if(i<=K) {
                    printf("Tom\n");
                    flag=1;
                    break;
                }//小于K的值无法没转换出来
                for(int j=i-K; j>=1; j-=K)
                    if(bucket[j]) {//可以转换
                        bucket[j]--;
                        bucket[i]++;
                        break;
                    }
                if(bucket[i]==0) {//没有转换的值
                    printf("Tom\n");
                    flag=1;
                    break;
                }
                bucket[i]--;//清空
            } else
                bucket[i]--;//清空
        }
        if(!flag)
            printf("Jerry\n");
        memset(bucket,0,sizeof(bucket));
    }
    return 0;
}

C(HDU 5092)

题目大意:给出一个N*M的矩阵,求出一条从第一行到最后一行的累和最小且最右的通路,从上到下输出通路通过点的列数,只要相邻都可以走(对角也可),但不能往上一层走

思路:直接对每个位置进行DP,当前位置选择从左上,上,右上取最优解,完成DP后回溯

代码

#include <bits/stdc++.h>
using namespace std;
int Photo[121][121],n,m,T,dp[121][121];
int main() {
    scanf("%d",&T);
    for(int p=1; p<=T; p++) {
        stack<int>S;
        int minn=INT_MAX,pos=0;
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++)
                scanf("%d",&Photo[i][j]);//扫描
        for(int i=1; i<=n; i++)
            dp[i][0]=dp[i][m+1]=Photo[i][0]=Photo[i][m+1]=INT_MAX;//预处理边界值
        for(int i=0; i<=m+1; i++)
            dp[1][i]=Photo[1][i];//同上
        for(int i=2; i<=n; i++)
            for(int j=1; j<=m; j++)
                dp[i][j]=Photo[i][j]+min(min(dp[i-1][j],dp[i-1][j-1]),dp[i-1][j+1]);
        //dp过程
        printf("Case %d\n",p);
        for(int i=1; i<=m; i++)
            if(dp[n][i]<=minn) {
                minn=dp[n][i];
                pos=i;
            }//获取最值
        S.push(pos);
        for(int i=n; i>=2; i--) {//回溯
            int t=S.top();
            if(dp[i][t]==dp[i-1][t+1]+Photo[i][t])
                S.push(t+1);
            else if(dp[i][t]==dp[i-1][t]+Photo[i][t])
                S.push(t);
            else
                S.push(t-1);
        }
        while(S.size()!=1) {
            printf("%d ",S.top());
            S.pop();
        }
        printf("%d\n",S.top());
        S.pop();
        memset(dp,0,sizeof(dp));
        memset(Photo,0,sizeof(Photo));
    }
    return 0;
}

J(HDU 5099)

题目大意:给出两个字符串,分成三个部分:A部分(1字符)B部分(1字符)C部分(4字符),比较A部分大小和BC部分大小,规则如下:A部分按照字典序比较,B+C部分,如果B相同,比较C部分,不同则比较C的前三位,按照字典序

思路:直接模拟

代码

#include <bits/stdc++.h>
using namespace std;
int T;
int main() {
    scanf("%d",&T);
    for(int i=1; i<=T; i++) {
        string a,b;
        cin >>a>>b;
        printf("Case %d:",i);
        int lena=a.length(),lenb=b.length();
        if(a[0]>b[0])
            printf(" >");
        else if(a[0]==b[0])
            printf(" =");
        else
            printf(" <");
        if(a[1]==b[1]) {
            a=a.substr(2,lena-2);
            b=b.substr(2,lenb-2);
            if(a>b)
                printf(" >");
            else if(a==b)
                printf(" =");
            else
                printf(" <");
        } else {
            a=a.substr(2,lena-3);
            b=b.substr(2,lenb-3);
            if(a>b)
                printf(" >");
            else if(a==b)
                printf(" =");
            else
                printf(" <");
        }
        putchar('\n');
    }
    return 0;
}

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值