【题解 && dp】CF82D Two out of Three

题目传送门

题目描述:

在这里插入图片描述


S o l u t i o n Solution Solution

很容易发现一个性质:不管前面选取哪些人,一定会有一个人是剩下的不被选取的。
因此我们设 f [ i ] [ j ] f[i][j] f[i][j]表示第 i i i次选取之后,剩下 j j j时的最少能量。
由于一次只能选择两个人,而每次前面只剩下一个人,所以选择第 i i i个人时,前三个人只能是 ( i ∗ 2 ) (i*2) i2, ( i ∗ 2 + 1 ) (i*2+1) (i2+1), ( j ) (j) (j),自己手玩很容易证明。

因此我们就可以进行转移:
在这里插入图片描述
因为一次选 2 2 2个人,所以最多选择 ⌈ n / 2 ⌉ \lceil n/2\rceil n/2次,而这样选完之后剩下 n + 1 n+1 n+1号人。
所以最后答案: f [ ⌈ n / 2 ⌉ ] [ n + 1 ] f[\lceil n/2\rceil][n+1] f[n/2][n+1]
至于方案,用一个数组记录转移方案即可
p r [ i ] [ j ] [ 0 / 1 / 2 ] pr[i][j][0/1/2] pr[i][j][0/1/2]表示当前状态中选的两个里的第一个和第二个,以及上一个状态下剩下的那一个

递归转移即可。


C o d e Code Code

#include<bits/stdc++.h>
using namespace std;

const int N = 2e3;
int n;
int a[N];
int f[N][N] , pr[N][N][3];

void Print(int x,int y){
	if (y == 0) return;
	Print(x-1,pr[x][y][2]);
	if (pr[x][y][0] <= n) printf("%d ",pr[x][y][0]);
	if (pr[x][y][1] <= n) printf("%d ",pr[x][y][1]);
	printf("\n");
}

int main(){
	scanf("%d",&n);
	for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
	memset(f,20,sizeof f);
	f[1][1] = max(a[2],a[3]);
	f[1][2] = max(a[1],a[3]);
	f[1][3] = max(a[1],a[2]);
	pr[1][1][0] = 2 , pr[1][1][1] = 3 , pr[1][1][2] = 0;
	pr[1][2][0] = 1 , pr[1][2][1] = 3 , pr[1][2][2] = 0;
	pr[1][3][0] = 1 , pr[1][3][1] = 2 , pr[1][3][2] = 0;
	
	int m = n+1>>1;
	for (int i = 2; i <= m; i++){
		int x = 2*i , y = 2*i+1;
		for (int j = 1; j < x; j++){
			 if (f[i][j] > f[i-1][j] + max(a[x],a[y])){
			 	f[i][j] = f[i-1][j] + max(a[x],a[y]);
			 	pr[i][j][0] = x , pr[i][j][1] = y , pr[i][j][2] = j;
			 }
			 if (f[i][x] > f[i-1][j] + max(a[j],a[y])){
			 	f[i][x] = f[i-1][j] + max(a[j],a[y]);
			 	pr[i][x][0] = j , pr[i][x][1] = y , pr[i][x][2] = j;
			 }
			 if (f[i][y] > f[i-1][j] + max(a[j],a[x])){
			 	f[i][y] = f[i-1][j] + max(a[x],a[j]);
			 	pr[i][y][0] = x , pr[i][y][1] = j , pr[i][y][2] = j;
			 }
		}
	}
	printf("%d\n",f[m][n+1]);
	Print(m,n+1);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值