GCJ 2009 Round 1C C (Bribe the Prisoners)

题意:

 

有P个相邻的牢房(序号1,2,…,P),每个牢房中关押着犯人一名

现在要释放Q个牢房中的犯人(序号给出),释放后牢房为空

每次释放一名时需要依次向左向右给其他牢房犯人每人一枚金币直到遇到空牢房为止

 

可以按照任何顺序释放犯人,输出所需最小金币数。

 

思路:

为方便理解,预处理出序号为0和序号为P+1的空牢房。

可以想到,如若释放了序号i(0<i<P+1)号牢房的犯人,则对0到i牢房组和 i到P+1牢房组的讨论完全独立且其最优解可构成0到P+1的最优解(算导将其称作最优子结构)

 

故可以用动态规划的思想:

 

定义状态dp[i][j] (0<=i<=j<=P+1) 为释放从i到j之间(不包括i,j)的所有需释放的犯人所需最小金币数(i与j之间无空牢房)

 

则可得转移方程为

 

考虑递归树的底层,转移顺序应该从短区间开始转移(枚举区间长度即可)

 

d[i][j] = (j-i-1)+d[i][v]+d[v][j] (i<v<j)

 

d[0][P+1]即为所求最优解。

 

P.S. 此处的未释放但需释放的犯人可以理解成隐式的空牢房。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define LL long long
#define MM 10010
#define MAX 1e16

LL dp[MM][MM];
int free_num[MM];

using namespace std;

int main()
{
	int P, Q;
	while(scanf("%d %d", &P, &Q)==2)
	{
		memset(dp, 0, sizeof(dp));

		for (int i = 1; i <= Q; ++i)
			scanf("%d", &free_num[i]);

		free_num[0] = 0;
		free_num[Q+1] = P+1;


		for (int diff = 2; diff <= Q+1; ++diff)
			for (int head = 0; head+diff <= Q+1; ++head)
                        {
                            LL temp = MAX;
                            int tail = head + diff;

			    for (int v = head+1; v < tail; ++v)
			        temp = min(temp, dp[head][v] + dp[v][tail]);

                            dp[head][tail] = temp + free_num[tail] - free_num[head] - 2;
                        }

		printf("%d\n", dp[0][Q+1]);
	}
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值