Cutting Sticks UVA

来源:互联网 发布:局域网网络协议 编辑:程序博客网 时间:2024/06/06 02:49

题目链接:点击打开链接

思路:
这道题明显就是一道区间dp了,也可以叫做线性dp,跟石子合并一样,为什么是区间dp呢, 根据题目意思,每一次切的花费为所切木棍的长度, 那么我们可能会尝试用贪心,去写,但是显然是不行的,为什么呢,用贪心的话只能保证当前最优解,并不能保证全局最优解,对于这道题来说,如果你选取了当前这一次的最优解,并不能保证从这个选择拓展出的下一次选择会是最优解, 所以贪心并不行。那么为什么用dp呢,我们分析发现,对于当前状态的一根木棍,对于可以切的每一个位置,都会产生一颗新的解答树,子解答树明显又会产生新的子解答树,并且父解答树只关心的子解答树的最优解(最优子结构!),那么就可以确定是dp了,那么接下来就是定义状态了,一开始我是想直接定义dp(i,j)

其中i,j为每一个位置,如果这个位置为切割点,就尝试状态转移,但是这样的话 ,o(n3)的复杂度 1000的大小 肯定超了,  然后我们看到题目是切割成n+1个小木棍  ,意思就是每一个切割点都会切,那么我们就可以定义状态dp(i,j),i,j为第几个切割点,这样n组最大为50,就不会超了, 那么怎么状态转移呢 , 根据我们刚才分析为什么用dp

的过程中差不多就可以得出结论了  ,我们根据分析的去模拟,我们的转移过程应该是找到最优的子状态,dp[i][j] = min(dp[i][k]+dp[k][j]+cost,dp[i][j]),注意把 0 和 l

丢进去, 画个图就知道了

ac代码

#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#include<sstream>#include<stack>#include<map>#include<set>#define LL long long#define INF 0x3f3f3f3fusing namespace std;int have[100];int l;int n;int dp[100][100];int main(){    while(~scanf("%d",&l)&&l)    {        scanf("%d",&n);        for(int i = 1 ;i<=n;i++)        {            int tmp;            scanf("%d",&tmp);            have[i] = tmp;        }        have[n+1] = l;        sort(have,have+n+1);        for(int i = 0 ;i<=n+1;i++)        {            for(int j = 0 ;j<=n+1;j++)            {                dp[i][j] = INF;                if(i==j)                    dp[i][j] = 0;                if(j-i==1)                {                    dp[i][j] = 0;                }            }        }        for(int len = 2 ; len<=n+1;len++)        {            for(int i = 0 ;i<=n;i++)            {             int j = i+len;             if(j>n+1)                continue;             for(int k = i+1;k<j;k++)             {                 dp[i][j]  = min(dp[i][k]+dp[k][j]+have[j]-have[i],dp[i][j]);             }               // printf("dp[%d][%d] = %d\n",i,j,dp[i][j]);            }        }        printf("The minimum cutting is %d.\n",dp[0][n+1]);    }}