zoukankan      html  css  js  c++  java
  • CF41D Pawn(三维DP)

    翻译: 题目描述: 国际象棋棋盘最底行站了一个兵。 它只有两种行动方式: 向上左或向上右走。 它可以选择从最低行哪个节点开始他的旅程。 每个格子上有0-9颗豌豆,而士兵想移动到最上一行并且积累到尽可能多的豌豆。同时,因为这个士兵必须把豌豆平均分给自己和他的k个兄弟,他所收集到的豌豆必须是k+1的倍数。请找到他可以收集到的最多豌豆,并确定他的操作序列。

    规定士兵不能手动扔出豌豆,并且他必须捡起所到达的每一个格子的所有豌豆。

    输入格式: 第一行三个整数n,m,k(2 <= n,m <= 100, 0 <= k <= 10)2<=n,m<=100,0<=k<=10) 行数、列数、士兵的兄弟们。 接下来一个n imes mn×m的矩阵,每个元素均是0-9的整数(不空格),描述该格的豌豆。第一行被认为是最上一行,最后一行被认为是最下一行。

    输出格式:

    如果不能收集到k+1倍数的豌豆,输出-1. 否则,输出第一行一个整数,为最多豌豆数;第二行一个整数,为士兵开始移动的位置;第三行包括n-1个字母L 或 R,表示士兵的行动序列。

    如果有多种收集到相同且是k+1倍数数量的豌豆,你可以任意输出一种方案。 Translated by @Maniac丶坚果

    题解:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=105;
    int a[maxn][maxn];
    string s[maxn];
    int n,m,p;
    int dp[maxn][maxn][15];
    int visit[maxn][maxn][15];
    //dp(i,j,k)表示第i行第j列的答案在模p的值等于k的前提下的最大值
    int main () {
        scanf("%d%d%d",&n,&m,&p);
        p++;
        for (int i=0;i<n;i++) cin>>s[i];
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                a[i][j]=s[i-1][j-1]-'0';
        for (int i=1;i<=m;i++) visit[n][i][a[n][i]%p]=1,dp[n][i][a[n][i]%p]=a[n][i];
        for (int i=n-1;i>=1;i--) {
            for (int j=1;j<=m;j++) {
                for (int k=0;k<p;k++) {
                    if (visit[i+1][j-1][k]) {
                        visit[i][j][(dp[i+1][j-1][k]+a[i][j])%p]=1;
                        dp[i][j][(dp[i+1][j-1][k]+a[i][j])%p]=max(dp[i][j][(dp[i+1][j-1][k]+a[i][j])%p],dp[i+1][j-1][k]+a[i][j]);
                    }
                    if (visit[i+1][j+1][k]) {
                        visit[i][j][(dp[i+1][j+1][k]+a[i][j])%p]=1;
                        dp[i][j][(dp[i+1][j+1][k]+a[i][j])%p]=max(dp[i][j][(dp[i+1][j+1][k]+a[i][j])%p],dp[i+1][j+1][k]+a[i][j]);
                    }
                } 
            }
        }
        int ans=-1;
        int u=-1;
        for (int i=1;i<=m;i++) {
            if (visit[1][i][0]&&dp[1][i][0]>ans) {
                ans=dp[1][i][0];
                u=i;
            }
        }
        printf("%d
    ",ans);
        if (ans==-1) return 0;
        string wjm="";
        int k=0;
        for (int i=1;i<n;i++) {
            int tt=dp[i][u][k]-a[i][u];
            k=tt%p;
            if (visit[i+1][u-1][k]&&dp[i+1][u-1][k]==tt) {
                wjm.push_back('R');
                u--;
            }
            else {
                wjm.push_back('L');
                u++;
            }
        }
        reverse(wjm.begin(),wjm.end());
        printf("%d
    ",u);
        cout<<wjm<<"
    ";
    } 
  • 相关阅读:
    GO语言常用标准库03---time包
    GO语言常用标准库02---os包
    GO语言常用标准库01---strings包
    GO语言复合类型05---递归
    GO语言练习---对切片进行排序
    GO语言复合类型04---映射
    GO语言复合类型03---切片
    GO语言复合类型02---数组
    [踩坑记录] windows10 应用商店打不开 代码: 0x80131500
    [Linux kali] Kali KDE桌面安装中文输入法 不能登录系统
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13490974.html
Copyright © 2011-2022 走看看