zoukankan      html  css  js  c++  java
  • 区间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
    ",dp2[1][n]);
    70     }
    71     return 0;
    72  
    73 }

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

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

  • 相关阅读:
    PHP面向对象练习
    PHP面向对象的特点
    PHP的构造函数和析构函数
    PHP面向对象
    AVL-TREE
    ReentrantLock
    treap-名次树-树堆
    细数那些我们熟悉的 排序!
    数据结构 - trie
    python 凸包(经纬度) + 面积[近似]
  • 原文地址:https://www.cnblogs.com/lnu161403214/p/8341805.html
Copyright © 2011-2022 走看看