题目大意
解题思路
为了解题方便,我们增加两个虚拟的罪犯,罪犯0
和罪犯Q+1
。然后我们:
- 定义 d p [ i ] [ j ] dp[i][j] dp[i][j]: 释放 ( i , j ) (i,j) (i,j)号罪犯需要的花费。
- 终态 d p [ 0 ] [ Q + 1 ] dp[0][Q+1] dp[0][Q+1]: 即释放所有罪犯的花费。
- 状态转移:
d
p
[
i
]
[
j
]
=
m
i
n
{
d
p
[
i
]
[
k
]
+
d
p
[
k
]
[
j
]
+
A
[
j
]
−
A
[
i
]
−
2
∣
i
<
k
<
j
}
dp[i][j] = min\{dp[i][k]+dp[k][j]+A[j]-A[i] - 2|i<k<j \}
dp[i][j]=min{dp[i][k]+dp[k][j]+A[j]−A[i]−2∣i<k<j}
(因为 m . . . n m...n m...n一共有 n − m + 1 n-m+1 n−m+1这么多罪犯,去除掉中间的一个,两边的两个,因此有 n − m + 1 − 3 = n − m − 2 n-m+1-3=n-m-2 n−m+1−3=n−m−2个) - 更新策略: 因为间距较长是从间距较短转移过来的, 因此按距离从小到大更新。
- 初态: d p [ i ] [ i [ = 0 , d p [ i ] [ i + 1 ] = 0 dp[i][i[ = 0, dp[i][i+1] = 0 dp[i][i[=0,dp[i][i+1]=0
- 复杂度: O ( Q 2 ) O(Q^2) O(Q2)
代码
#include<iostream>
using namespace std;
const int inf = 1 << 20;
const int MAX = 10005;
int dp[MAX][MAX];
int main()
{
int P, Q;
int A[MAX];
while(cin >> P >> Q)
{
for(int i=1; i<=Q; i++)
cin >> A[i];
A[0] = 0;
A[Q+1] = P+1;
for(int i=0; i<=Q+1; i++)
for(int j=0; j<=Q+1; j++)
dp[i][j] = inf;
for(int i=0;i<=Q+1; i++)
dp[i][i] = 0;
for(int i=0; i<=Q; i++)
dp[i][i+1] = 0;
for(int l=3; l<=Q+2; l++)
{
for(int i=0; i+l-1<=Q+1; i++)
{
int j = i+l-1;
for(int k=i+1; k<j; k++)
{
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + A[j] - A[i] - 2);
}
}
}
cout << dp[0][Q+1] << endl;
}
return 0;
}