首页 > 代码库 > 【NOIP2010】【P1317】乌龟棋
【NOIP2010】【P1317】乌龟棋
似乎很像搜索的DP(应该也可以用搜索写)
原题:
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行N 个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中M 张爬行卡片,分成4 种不同的类型(M 张卡片中不一定包含所有4 种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
对于100%的数据有1 ≤ N≤ 350,1 ≤M≤ 120,且4 种爬行卡片,每种卡片的张数不会
超过40;0 ≤ ai ≤ 100,1 ≤ i ≤ N;1 ≤ bi ≤ 4,1 ≤ i ≤M。
刚开始还以为是背包,不过这题不能用背包解决,因为背包中物品的价值是固定的,放入顺序对总价值没有影响,但是这里如果把卡片看成物品的话这个物品的价值会根据前面卡片使用顺序改变,所以不能用背包
思路就是开一个四维的f,四重循环枚举当前每种卡片用了多少,然后从上一层转移过来最大值,最后加上a(i+j*2+p*3+q*4+1)即可
应该也可以用搜索解决,不过就算搜索本质还是DP,只不过上面用for是根据前面已经得到的结果的优化现在的,搜索是根据现在的值优化以后的,两种写法代码复杂度和时间复杂度应该都差不多
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int f[50][50][50][50]; 8 int n,m,a[1100],num[5]; 9 int main(){//freopen("ddd.in","r",stdin);10 cin>>n>>m;11 for(int i=1;i<=n;i++) cin>>a[i];12 int _id;13 for(int i=1;i<=m;i++){ cin>>_id; num[_id]++;}14 for(int i=1;i<=num[1]+1;i++)15 for(int j=1;j<=num[2]+1;j++)16 for(int p=1;p<=num[3]+1;p++)17 for(int q=1;q<=num[4]+1;q++){18 f[i][j][p][q]=max(f[i][j][p][q],f[i-1][j][p][q]);19 f[i][j][p][q]=max(f[i][j][p][q],f[i][j-1][p][q]);20 f[i][j][p][q]=max(f[i][j][p][q],f[i][j][p-1][q]);21 f[i][j][p][q]=max(f[i][j][p][q],f[i][j][p][q-1]);22 f[i][j][p][q]+=a[i-1+(j-1)*2+(p-1)*3+(q-1)*4+1];23 }24 cout<<f[num[1]+1][num[2]+1][num[3]+1][num[4]+1]<<endl;25 return 0;26 }
【NOIP2010】【P1317】乌龟棋