一行监狱里面住着P个连续的囚徒,现在有一些囚徒需要释放,但是如果释放囚徒则需贿赂两边所有相邻的囚徒(直到遇到空位或者数组越界),求贿赂的最小值。
此题用动态规划来解决:
dp[i] [j] 表示释放A(i) 到A(j)的所有囚犯,但不包括A(i) 和A(j),假定A(i) 和A(j)已经被释放,那么就形成两个空位。
释放期中一个囚徒,花费有如下三个方面组成:
1.自己的花费(区间长度);
2.释放所有左区间里所需要释放囚徒的花费;
3.释放所有右区间里所需要释放囚徒的花费;
只需要不断枚举下一个在区间内囚徒的被释放的总花费花费,找到其最小值,再加上区间长度,便可得到总的花费的最小值。
注意的是必须把两面“墙壁”添加到囚徒数组中,因为他们是两个空位,所有的囚徒都在其间,
所以,dp[0][Q+1]包含了所有囚徒,即为所求的最小值。
题源来自《挑战程序竞赛》第二版 130页。
//
// 130_bribe the prisoners.cpp
// changlle
//
// Created by user on 1/7/16.
// Copyright (c) 2016 user. All rights reserved.
//
#include <iostream>
using namespace std;
const int INF=10000;
int P=20;
int Q=3;
int A[5]={0,3,6,14,21};
int dp[5][5];
void solve() {
A[0]=0;
A[Q+1]=P+1; //添加墙壁,由此可以包含所有囚徒
for (int q=0;q<=Q;q++)
dp[q][q+1]=0;//初始化,紧挨着的囚徒之间没有需要释放的囚徒
for (int w=2; w<=Q+1;w++){
for (int i=0; i+w<=Q+1;i++){
//计算dp[i][j]
int j=i+w, t=INF;
for (int k=i+1;k<j;k++)
t=min(t,dp[i][k]+dp[k][j]);
dp[i][j]=t+A[j]-A[i]-2;
}
}
}
int main() {
solve();
cout<<dp[0][Q+1]<<endl;
}