切木棍Cutting Sticks【区间DP+记忆化搜索】

传送门
d ( i , j ) d(i,j) d(i,j)为切割小木棍i~j的最优费用,则 ,其 中最后一项 a [ j ] - a [ i ] a[j]-a[i] a[j]a[i]代表第一刀的费用。切完之后,小木棍变成 i ~ k i~k ik k ~ j k~j kj两部分,状态转 移方程由此可得。把切割点编号为 1 ~ n 1~n 1n,左边界编号为0,右边界编号为 n + 1 n+1 n1,则答案 为 d ( 0 , n + 1 ) d(0,n+1) d(0,n1)
状态有 O ( n 2 ) O(n2) O(n2)个,每个状态的决策有 O ( n ) O(n) O(n)个,时间复杂度为 O ( n 3 ) O(n3) O(n3)
记忆化搜索:

#include
using namespace std;
const int N=50+5;
int n,L,a[N],vis[N][N],d[N][N];

int dp(int i,int j){
     
	if(i>=j-1) return 0;
	if(vis[i][j]) return d[i][j];
	vis[i][j]=1;
	int& ans=d[i][j];
	ans=-1;
	for(int k=i+1;k<j;k++){
     
		int v=dp(i,k)+dp(k,j)+a[j]-a[i];
		if(ans<0||v<ans) ans=v;
	}
	return ans;
}

int main(){
     
	while(cin>>L>>n,L){
     
		for(int i=1;i<=n;i++) cin>>a[i];
		a[0]=0;a[n+1]=L;
		memset(vis,0,sizeof(vis));
		printf("The minimum cutting is %d.\n", dp(0, n+1)); 
	}
}

递推:

#include
using namespace std;
const int N=50+5;
int n,L,a[N],d[N][N];
int main(){
     
	while(cin>>L>>n,L){
     
		for(int i=1;i<=n;i++) cin>>a[i];
		a[0]=0;a[n+1]=L;
		memset(d,0,sizeof(d));
		for(int i=0;i<=n+1;i++) d[i][i]=0;
		for(int len=1;len<=n+1;len++){
     
			for(int i=0;i+len<=n+1;i++){
     
				int j=i+len;
				if(j<=n+1){
     
						for(int k=i+1;k<j;k++){
     
						int v=d[i][k]+d[k][j]+a[j]-a[i];
						if(d[i][j]==0||v<d[i][j]) d[i][j]=v;
					}
				}
			}
		}
		printf("The minimum cutting is %d.\n", d[0][n+1]); 
	} 
}

你可能感兴趣的:(区间DP)