这个题目蛮有新意的,一度导致我没看透他是区间DP
给一个0-L长度的木板,然后给N个数,表示0-L之间的某个刻度,最后要用刀把每个刻度都切一下 使其断开,然后每次分裂的cost是分裂前的木板的长度。求整个分开之后的最小cost。
当时下意识就想到类似花瓶插花问题,即dp[i][j],表示第i个事物放在第j次动作来的最小代价,但是当我写起来发现很麻烦,我是以刻度点来表示的i,结果发现处理起来相当麻烦,因为实体实际是一块一块的小木板,以点作为转移变量 不仅要加诸多限制,而且加完后发现会互相矛盾,原因在于点本身不稳定,他的切割不仅涉及次数,还涉及左右板块的各种组合可能。
后来想了一下,此题反过来想,其实是从小木块堆叠成大木块,从单个的组合为成对的 然后组合成3个或者4个的。。。这不是就个区间dp吗。。然后问题就变得超级简单啦。。。连我都不相信原本让我写的这么复杂的。。反过来一想就这么几行。。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int dp[55][55]; int L,sz[55][2]; int A[55],n; int main() { while (scanf("%d",&L) && L) { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&A[i]); memset(dp,-1,sizeof dp); A[n+1]=L; n++; sort(A+1,A+n+1); for (int i=1;i<=n;i++){ sz[i][0]=sz[i-1][1]; sz[i][1]=A[i]; dp[i][i]=0; } for (int i=1;i<n;i++){ for (int j=1;j+i<=n;j++){ int k=j+i; int val=sz[k][1]-sz[j][0]; for (int w=j;w<=k;w++){ int tmp=dp[j][w]+dp[w+1][k]+val; if (dp[j][k]<0){ dp[j][k]=tmp; } else{ dp[j][k]=min(dp[j][k],tmp); } } } } printf("The minimum cutting is %d.\n",dp[1][n]); } return 0; }
UVA 10003 区间DP
时间: 2024-11-05 16:12:06