hdu5115-Dire Wolf(区间dp)

这题是区间DP。看见dp就成傻逼了。

题目的意思是ai表示每头狼的本身具备的攻击力,bi表示能提供给相邻狼的攻击力,以什么样的顺序去杀狼可以使狼对人的攻击最少。

且如果狼被杀了,就不能为相邻的狼提供攻击力了。

动态转移方程为dp[i][j]=min(dp[i][k]+dp[k][j]+a[k]+a[i]+a[j],dp[i][j])(j<k<i);

i表示以第i头狼为右端点(还未斩杀),j表示以第j头狼为左端点(还未斩杀)。

dp[i][j]记录的为以i,j未选时,那个而i-j内的点已选好的最小的攻击。

(这道题做的我。。。。花了差不多一天时间,中间想想发发呆,就这种状态。还是懒,,,,然而现在还没有想的太明白。。。。。。。。)。

首先a,b数组两端要多加一位,a[0]=0;b[0]=0;a[p+1]=0;b[p+1]=0;

因为要把所有的狼都杀完,因为每次都要有两端,所以要杀完就必须是0-p+1内的编号1到p的狼,1左,p右端必须要有个端点。最后答案就是dp[p+1][0];

从后往前说dp比较好理解,dp[p+1][0]为最后一个状态,那么要最优就看最后选走的是哪一个,那么可以得到,dp[p+1][0]=min(dp[p+1][k]+dp[k][0]+a[k]+b[p+1]+b[0]);

这里面的k就是最后取走的,在求就要求dp[p+1][k]的最优,这个以p+1为左端以k为右端,当然还是这个状态转移方程,同理求dp[k][0];

然后反着推理解了,就从正着来写成递推。

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<stdlib.h>
 5 #include<string.h>
 6 using namespace std;
 7 long long N=1e16;
 8 typedef long long ll;
 9 int main(void)
10 {
11     int i,j,k,p,q;
12     ll dp[300][300];
13     ll a[300];
14     ll b[300];
15     scanf("%d",&k);
16     for(i=1; i<=k; i++)
17     {
18         scanf("%d",&p);
19         memset(a,0,sizeof(a));
20         memset(b,0,sizeof(b));
21         memset(dp,0,sizeof(dp));
22         for(j=1; j<=p; j++)
23             scanf("%lld",&a[j]);
24         for(j=1; j<=p; j++)
25             scanf("%lld",&b[j]);
26         int n,m,t;
27         for(n=2; n<=p+1; n++)//首位是0,因为至少需要3个数才能有两个端点,中间有数,所以从二开始,dp[i][j](i-j<3价值都为0)
28         {
29             for(m=n-2; m>=0; m--)
30             {
31                 dp[n][m]=dp[n][n-1]+dp[n-1][m]+a[n-1]+b[n]+b[m];
32                 for(t=n-1; t>m; t--)//找最优的断点
33                 {
34                     dp[n][m]=min(dp[n][t]+dp[t][m]+b[n]+a[t]+b[m],dp[n][m]);
35                 }
36             }
37         }
38         printf("Case #%d: %lld
",i,dp[p+1][0]);
39     }
40     return 0;
41 }
油!油!you@
原文地址:https://www.cnblogs.com/zzuli2sjy/p/4955774.html