区间DP(hdu5900)

题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5900

大意:There are N pairs of numbers,Each pair consists of a key and a value,Now you need to move out some of the pairs to get the score.You can move out two continuous pairs,if and only if their keys are non coprime(their gcd is not one).The final score you get is the sum of all pair’s value which be moved out. May I ask how many points you can get the most?

N<=300,可用O(n3)算法过,显然是区间dp。

以区间dp分析,dp[i][j]来自dp[i][k]+dp[k+1][j]转移,还有就是来自本区间(因为本区间在前面是没有计算过的)(如在本题中先中间的消去,然后i与j消去)。

所以在本题中,只要判断并计算一下本区间的,然后再考虑转移就行了。

这里判断某区间能否消去,可以用前缀和,虽然我用了麻烦的方法先预处理了区间能否消去。

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<queue>
 4 #include<string.h>
 5 using namespace std;
 6 typedef long long ll;
 7 
 8 struct Node{
 9     ll k,v;
10 }node[305];
11 int cos1[305][305]={0}; //能否消去 
12 ll dp2[305][305];
13 ll gcd(ll x,ll y)
14 {    if(y==0) return x;
15     return gcd(y,x%y);
16 }
17 int main()
18 {    int T;
19     scanf("%d",&T);
20     while(T--)
21     {    int n;
22         scanf("%d",&n);
23         memset(cos1,0,sizeof(cos1));
24        
25         memset(dp2,0,sizeof(dp2));
26         for(int i=1;i<=n;i++)
27             scanf("%lld",&node[i].k);
28         for(int i=1;i<=n;i++)
29             scanf("%lld",&node[i].v);
30         for(int j=2;j<=n;j++)
31         for(int i=j-1;i>=1;i--)
32         {
33             if((j-i)%2==0) continue;
34             if((j-i)==1)
35             {
36                 if(gcd(node[i].k,node[j].k)!=1) cos1[i][j]=1;
37             } 
38             else
39             {    if(cos1[i+1][j-1]==1&&gcd(node[i].k,node[j].k)!=1) cos1[i][j]=1;
40                 else
41                 {    int k;
42                     for(k=1;i+k+1<j;k++)
43                     if(cos1[i][i+k]==1&&cos1[i+k+1][j]==1) break;
44                     if(i+k+1<j)    cos1[i][j]=1;
45                 }
46                 
47             }
48             
49         }
50         
51     for (int l = 2; l <= n; ++l) 
52     {
53     for (int i = 1, j; i <= n - l + 1; ++i) 
54         {    j = i + l - 1;
55             if(gcd(node[i].k,node[j].k)!=1) 
56             {
57             if((j-i)==1) dp2[i][j]=node[i].v+node[j].v;
58             if((j-i)>1&&cos1[i+1][j-1]==1) dp2[i][j]=node[i].v+node[j].v+dp2[i+1][j-1];
59             }
60             else  dp2[i][j]=0;
61        
62         for (int k = i; k < j; ++k) {
63            dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[k+1][j]);
64         }
65         
66         }
67     }
68 
69         printf("%lld\n",dp2[1][n]);
70     }
71     return 0;
72  
73 }

其实代码中两个循环是一个意思,都是枚举所有区间,但要保证在计算某个区间前它的子区间都已计算过。

 

开始分析区间dp问题的时候我觉得采用普通dp一样的分析,假设多一单位长度,分析多的这一单位长度的影响,还有子区间都已计算好。。。。

转载于:https://www.cnblogs.com/lnu161403214/p/8341805.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值