P1622 释放囚犯

${color{Cyan}{>>Question}}$

随着题量的上升,见的模型也越来越多

动态规划,明确的状态定义,明确的转移,明确的边界(有时边界比转移更重要)

比如此题,最开始我并没有看出是区间$dp$,但我突然想起紫书上一道题,"割木棍"

仔细想想,几乎与此题一样

最开始,我定义$f[i,j]$表示端点$i$到端点$j$的最小代价,枚举切割点$k$

$$f[i,j] = underset{i<k<j}{min}left {f[i,k]+f[k,j]  ight }+(a[j]-a[i]+1)-1$$

但这样定义,$f$转移时就发生了重合,如下图

改变定义,令$f[i,j]$表示$i$到$j$(不包括端点$i$和$j$)的最小代价

$$f[i,j] = underset{i<k<j}{min}left {f[i,k]+f[k,j]  ight }+(a[j]-a[i]-1)-1$$

这样便是对的,如下图

代码如下

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #define ll long long
 6 //#include <stack>
 7 using namespace std;
 8 
 9 template <typename T> void in(T &x) {
10     x = 0; T f = 1; char ch = getchar();
11     while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
12     while(isdigit(ch)) {x = 10*x + ch - '0'; ch = getchar();}
13     x *= f;
14 }
15 //------------------------------------------------------------
16 
17 const int N = 105;
18 
19 int m,n,a[N],f[N][N];
20 
21 int dp(int i,int j) {
22     int &_f = f[i][j];
23     if(_f) return _f;
24     //if(i == j) return 0;
25     if(i+1 == j) return 0;
26     int tmp = 0x3f3f3f3f;
27     for(int k = i+1;k <= j-1; ++k) tmp = min(tmp,dp(i,k)+dp(k,j));
28     return _f = tmp+a[j]-a[i]-2;//-2
29 }
30 
31 int main() {
32     freopen("0.in","r",stdin);
33     in(m); in(n);
34     for(int i = 1;i <= n; ++i) in(a[i]);
35     sort(a+1,a+n+1); a[0] = 0; a[n+1] = m+1;//0,m+1
36     //memset(f,0x3f,sizeof(f));
37     cout << dp(0,n+1);
38     return 0;
39 }
原文地址:https://www.cnblogs.com/mzg1805/p/11440325.html