首页 > 技术文章 > 洛谷——动态规划

wsdestdq 2017-06-18 20:08 原文

1.P1057 传球游戏

题目描述

上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。

游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师在此吹哨子时,传球停止,此时,拿着球没有传出去的那个同学就是败者,要给大家表演一个节目。

聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。

输入输出格式

输入格式:

输入文件ball.in共一行,有两个用空格隔开的整数n,m(3<=n<=30,1<=m<=30)。

输出格式:

输出文件ball.out共一行,有一个整数,表示符合题意的方法数。

输入输出样例

输入样例#1:
3 3
输出样例#1:
2

说明

40%的数据满足:3<=n<=30,1<=m<=20

100%的数据满足:3<=n<=30,1<=m<=30

2008普及组第三题

 思路:

  我们可以先把这个圈展开,那么球是不是就只有从左边传来和从右边传来两种情况呢?

    所以wuli转移方程就到手啦!!

       再想一想,还有两个特殊情况呢,第一个和最后一个。。。。

    无奈的加特判喽~~

上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n,m,f[31][31];//f[i][j]表示第i个人传j次所能获得的次数

int main() {
    cin>>n>>m;
    memset(f,0,sizeof(f));
    f[1][0]=1;//设置第一人为传回来的人,传0次(相当于还没穿出去)有1种传回的情况
    for(int j=1; j<=m; j++)
        for(int i=1; i<=n; i++) {
            if(i==1)
                f[i][j]=f[n][j-1]+f[i+1][j-1];//相当于把数组的线性绕成圈,才能循环传递
            else if(i==n)
                f[i][j]=f[1][j-1]+f[i-1][j-1];
            else f[i][j]=f[i-1][j-1]+f[i+1][j-1];//当前人的次数等于上次左边的人的次数加右边人的次数
        }
    cout<<f[1][m];
    return 0;
}

2.P1541 乌龟棋

题目背景

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。

题目描述

乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

输入输出格式

输入格式:

输入文件的每行中两个数之间用一个空格隔开。

第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。

第2行N个非负整数,a1a2……aN,其中ai表示棋盘第i个格子上的分数。

第3行M个整数,b1b2……bM,表示M张爬行卡片上的数字。

输入数据保证到达终点时刚好用光M张爬行卡片。

输出格式:

输出只有1行,1个整数,表示小明最多能得到的分数。

输入输出样例

输入样例#1:
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
输出样例#1:
73

说明

每个测试点1s

小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是1,所以自动获得第1格的分数6。

对于30%的数据有1≤N≤30,1≤M≤12。

对于50%的数据有1≤N≤120,1≤M≤50,且4种爬行卡片,每种卡片的张数不会超过20。

对于100%的数据有1≤N≤350,1≤M≤120,且4种爬行卡片,每种卡片的张数不会超过40;0≤ai≤100,1≤i≤N;1≤bi≤4,1≤i≤M。

 思路:

  共有1、2、3、4四种卡片,那么当前位置就可以是从-1、-2、-3、-4的位置转移过来的,要在这四种情况中取最优,别忘了加上分数。。

上代码:

#include <iostream>
#include <cstdio>
using namespace std;
int now,scr[360],crd[5],maxn,m,n,dp[41][41][41][41];
int main() {
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        scanf("%d",&scr[i]);
    for(int i=1; i<=m; i++) {
        int x;
        scanf("%d",&x);
        crd[x]++;
    }
    for(int i=0; i<=crd[1]; i++)
        for(int j=0; j<=crd[2]; j++)
            for(int k=0; k<=crd[3]; k++)
                for(int l=0; l<=crd[4]; l++) {
                    if(i) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i-1][j][k][l]);
                    if(j) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j-1][k][l]);
                    if(k) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k-1][l]);
                    if(l) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k][l-1]);
                    //以上四行是由上阶段开始枚举每一张牌来选出目标阶段的最优解
                    dp[i][j][k][l]+=scr[i+j*2+k*3+l*4+1];              //加上当前格子的得分
                }
    cout<<dp[crd[1]][crd[2]][crd[3]][crd[4]];
    return 0;
}

 

自己选的路,跪着也要走完!!!

推荐阅读