2022.03.14乌龟棋

在这里插入图片描述
在这里插入图片描述

前言:

做该题时,困在了状态转移方程中,总结出一个新知识:
状态转移时,需要遍历每一种状态。但设计状态转移方程时,只需要考虑当前状态由哪些状态转移得到即可。

思路:动态规划

定义状态:dp[i][j][k][l],即使用i,j,k,l张第1,2,3,4种卡牌的最高得分。
状态转移:对于状态[i][j][k][l], 可能是最后使用了第1类卡牌得到,也可能是最后使用了第二类卡牌得到,也可能是第3类或者第四类。一共就这三种情况,状态转移方程如下:
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1-1][p2][p3][p4]+a[cur]);
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2-1][p3][p4]+a[cur]);
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3-1][p4]+a[cur]);
dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3][p4-1]+a[cur]);
其中a[cur]表示使用了p1,p2,p3,p4卡牌的最后位置,这个位置是固定的。

代码

	int n,m;
	int[] a = new int[400];
	int[] cnt = new int[5];
	int[][][][] dp = new int[41][41][41][41];
	void test() throws IOException  {
		Reader cin = new Reader();
		n = cin.nextInt();
		m = cin.nextInt();
		for(int i = 1; i <= n; i++) a[i] = cin.nextInt();
		for(int i = 1; i <= m; i++) cnt[cin.nextInt()]++;
		
		dp[0][0][0][0] = a[1];
		for(int p1 = 0; p1 <= cnt[1]; p1++) {
			for(int p2 = 0; p2 <= cnt[2]; p2++) {
				for(int p3 = 0; p3 <= cnt[3]; p3++) {
					for(int p4 = 0; p4 <= cnt[4]; p4++) {
						int cur = 1+p1+2*p2+3*p3+4*p4;
						if(p1 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1-1][p2][p3][p4]+a[cur]);
						if(p2 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2-1][p3][p4]+a[cur]);
						if(p3 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3-1][p4]+a[cur]);
						if(p4 > 0) dp[p1][p2][p3][p4] = Math.max(dp[p1][p2][p3][p4], dp[p1][p2][p3][p4-1]+a[cur]);
					}
				}
			}
		}
		
		System.out.println(dp[cnt[1]][cnt[2]][cnt[3]][cnt[4]]);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值