P1622 释放囚犯
随着题量的上升,见的模型也越来越多
动态规划,明确的状态定义,明确的转移,明确的边界(有时边界比转移更重要)
比如此题,最开始我并没有看出是区间$dp$,但我突然想起紫书上一道题,"割木棍"
仔细想想,几乎与此题一样
最开始,我定义$f[i,j]$表示端点$i$到端点$j$的最小代价,枚举切割点$k$
有
$$f[i,j] = \underset{i<k<j}{min}\left \{f[i,k]+f[k,j] \right \}+(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] \right \}+(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 }