zoukankan      html  css  js  c++  java
  • D. Pawn(记忆化搜索)

    https://codeforces.com/contest/41/problem/D

    题意翻译

    翻译: 题目描述: 国际象棋棋盘最底行站了一个兵。 它只有两种行动方式: 向上左或向上右走。 它可以选择从最低行哪个节点开始他的旅程。 每个格子上有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倍数数量的豌豆,你可以任意输出一种方案。 

    这题和数塔很相似,不过是多了一个要求就是还要满足获得的最大值是K+1的倍数,那么只需要多定义一维表示模K+1为多少的状态即可,定义dp[i][j][k]为从i,j为起点往下走能获得的最大值,且最大值模K+1为k。 转移的话就由它的左下角格子和右下角格子转移来即可,用的是填表法,不过大佬说可以用刷表法写,感觉应该差不多。

    #include<bits/stdc++.h>
    using namespace std;
    #define ls rt<<1
    #define rs (rt<<1)+1
    #define ll long long
    #define fuck(x) cout<<#x<<"     "<<x<<endl;
    typedef pair<int,int>pii;
    const int maxn=1e6+10;
    int d[4][2]= {1,0,-1,0,0,1,0,-1};
    int dp[105][105][15],mp[105][105],vis[105][105],n,m,k;
    pii path[105][105][15];
    void dfs(int x,int y)
    {
        if(vis[x][y]||x>n||x<1||y>m||y<1)
            return ;
        vis[x][y]=1;
        dfs(x+1,y-1);
        dfs(x+1,y+1);
        for(int i=0; i<=k; i++)
        {
            if(dp[x+1][y+1][i]!=-1&&dp[x][y][(i+mp[x][y])%(k+1)]<dp[x+1][y+1][i]+mp[x][y])
                dp[x][y][(i + mp[x][y]) % (k + 1)] = dp[x + 1][y + 1][i] + mp[x][y], path[x][y][(i + mp[x][y]) %(k + 1)] = make_pair(x + 1, y + 1);
            if(dp[x+1][y-1][i]!=-1&&dp[x][y][(i+mp[x][y])%(k+1)]<dp[x+1][y-1][i]+mp[x][y])
                dp[x][y][(i + mp[x][y]) % (k + 1)] = dp[x + 1][y - 1][i] + mp[x][y], path[x][y][(i + mp[x][y]) %(k + 1)] = make_pair(x + 1, y - 1);
        }
    }
    int main(){
        stack<pii>sta;
        int maxx=-1,pos,mod=0,tmp;
        memset(dp,-1,sizeof(dp));
        while(!sta.empty())
            sta.pop();
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++)
            {
                char ch;
                scanf(" %c",&ch);
                mp[i][j]=ch-'0';
            }
        for(int j=1;j<=m;j++){
            vis[n][j]=1;
            dp[n][j][mp[n][j]%(k+1)]=mp[n][j];
        }
        for(int j=1; j<=m; j++)
            dfs(1,j);
        for(int j=1; j<=m; j++)
            if(dp[1][j][0]>maxx)
                maxx=dp[1][j][0],pos=j;
        cout<<maxx<<endl;
        if(maxx!=-1)
        {
            pii now=make_pair(1,pos);
            while(now.first!=0){
                sta.push(make_pair(now.first,now.second));
                tmp=(mod-mp[now.first][now.second]%(k+1)+k+1)%(k+1);
                now=path[now.first][now.second][mod];
                mod=tmp;
            }
            int yy=sta.top().second;sta.pop();
            cout<<yy<<endl;
            while(!sta.empty()){
                if(sta.top().second>yy)
                    cout<<"R";
                else
                    cout<<"L";
                yy=sta.top().second;
                sta.pop();
            }
            cout<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    Runloop运行循环的理解
    GCD dispatch_apply基本使用
    GCD信号量semaphore控制线程并发数
    多线程GCD dispatch_once_t/dispatch_barrier_<a>sync/dispatch_group_t
    iOS开发常用宏定义
    OC方法可变参数
    GCD的基本使用
    iOS实用小工具
    项目中实用第三方框架
    NSTimer内存泄漏问题
  • 原文地址:https://www.cnblogs.com/eason9906/p/11754709.html
Copyright © 2011-2022 走看看