2009 Round 1C C Bribe the Prisoners

题目可以在网上找,这里主要讲思路

这是一个最优子,即最优解可以由子问题的最优解得到。主要思路在下面

 

注意:(1)dp[i][j]表示的是,将从A[i]号囚犯到A[j]号囚犯(不含两端的囚犯)的连续部分里的所有囚犯都释放时,所需的最少金币总数。以dp[1][4]为例,这是把A[I]和A[4]之外的牢房都视为空牢房,并且把A[1]和A[4]当做两端的墙壁,求出的释放A[2]和A[4]所需的金币数。因此,如果输入P=8,Q=2, A = {3,4},可以得到A[0][2] = 2。如果这一点理解错了,就会以为A[0][2]应该是7,那么代码就无法解释通了。

          (2)下面代码中的min(temp, dp[head][v] + dp[v][tail]); 求的是释放完A[v]后,将牢房分为两个部分,分别释放左边与右边的按(1)中所说的囚犯时,左右两边按(1)中所述需要的金币总数。

          (3)free_num[tail] - free_num[head] - 2是对于dp[head][tail],最初释放一个囚犯时,所需要的金币数(边界也和(1)中描述的一样)。然后加上(2)中左右两边的金币数,记得A[head] A[tail]范围内释放相应囚犯的金币数。

          (4)之所以会有min,是因为释放囚犯k的时候,无论k是多少,金币都一样。但k的不同会导致左右两边释放时金币总数的不同。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <string>
#include <map>
#include <iostream>
using namespace std;
 
#define INF 1e9+7
#define MAXN 100010
 
int P,Q;
int a[MAXN];
int dp[MAXN][MAXN];//dp[i][j]表示i到j内囚犯释放所需要的最少金币
 
 
int main()
{
    scanf("%d%d",&P,&Q);
    for(int i=1;i<=Q;i++)
        scanf("%d",a+i);
    a[0]=0,a[Q+1]=P+1;//为了处理两端情况
    for(int i=0;i<=Q;i++)
    {
        dp[i][i+1]=0;
    }
    //每一次长度加一,比如在计算长度为3的区间,长度为2和1的区间已经计算过了。
    for(int w=2;w<=Q+1;w++)
    {
        for(int i=0;i+w<=Q+1;i++)
        {
            int j=i+w;
            int ans=INF;
            for(int k=i+1;k<j;k++)
            {
                ans=min(ans,dp[i][k]+dp[k][j]);
            }
            dp[i][j]=ans+a[j]-a[i]-2;//a[j]-a[i]-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、付费专栏及课程。

余额充值