dp入门 专题记录 2017-7-26

POJ3176-Cow Bowling

题目大意:现有n行数,以金字塔的形式排列,即第一行一个数字,第二行2个数字,依次类推,现在需要找一条从第一层到第n层的路线,使得该路线上的所有点的权值和最大

思路:根据分析可以得出状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]),dp[i][j]表示以第i行第j个位置作为终点的的线路中的最大权值。

#include <iostream>
using namespace std;
const int N = 360;
int s[N][N];
int dp[N][N];
int main ()
{
    int n;cin >> n;
    for(int i=1;i <= n;i++)
        for(int j=1;j <= i;j++)
            cin >> s[i][j];
    for(int i=n;i ;i--)
    {
        for(int j=1;j <= i;j++)//从下网上依次找到最大的
        {
            dp[i][j] = s[i][j] +  max(dp[i+1][j],dp[i+1][j+1]);
        }

    }
    cout<< dp[1][1]<<endl;

    return 0;
}

A

Poj 2229(dp)

题目大意:求把一个整数分解为2的幂的和共有几种方案

6=1+1+1+1+1+1

6=1+1+1+1+2

6=1+1+2+2

6=1+1+4

6=2+2+2

6=2+4

思路1:

如果i为奇数,肯定有一个1,把f[i-1]的每一种情况加一个1就得到fi,所以f[i]=f[i-1]

如果i为偶数,如果有1,至少有两个,则f[i-2]的每一种情况加两个1,就得到i,

      如果没有1,则把分解式中的每一项除2,则得到f[i/2]  (比如 4 = 2+2 ,4 = 4  除2后就变成 2 = 1 + 1 , 2 = 2)

所以f[i]=f[i-2]+f[i/2]

#include <iostream>
#include <cstdio>

using namespace std;
const int mod = 1e9 ;
const int maxn = 1000000 + 5;
typedef long long LL;

LL dp[maxn];

int main()
{
    int n;
    cin >> n;

    dp[0] = 1,dp[1] = 1;
    for(int i=2;i<=n;i++)
    {
        if(i & 1)//奇数
            dp[i] = dp[i-1];
        else//偶数
        {
            dp[i] = dp[i-2] + dp[i/2],dp[i] %= mod;
        }
    }
    cout<< dp[n] <<endl;
    return 0;
}

B_递推

思路2:

题目分析: d[i][v]  表示前i物品之和为v的最多数量,  有状态转移方程 d[i][v]  = sum( d[i-1][v-k*c[i]] |   0 < k*c[i] <=v)

利用完全背包O(vn)优化的思想, 这里思想是相同的,则d[v] += d[v-c[i]]

#include <iostream>
#include <cstdio>

using namespace std;
const int mod = 1e9;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
typedef long long LL;
int s[20];
LL dp[maxn];

int main()
{
    int n;
    scanf("%d",&n);
    s[0] = 1;
    for(int i=1;i<20;i++)
        s[i] = s[i-1]*2; //打表记录 2的0-20次方
    dp[0] = 1;
    for (int i =0;i < 20; i++){
        if(s[i] > n) break;
        for(int j=s[i];j <= n ;j++){
            dp[j] +=  dp[ j-s[i] ] ;
            if(dp[j] > mod )
                dp[j] %= mod;
        }
    }
    printf("%lld",dp[n]);
    return 0;
}

B_完全背包 容易T

poj 2385 Apple Catching

题意:有两棵苹果树,标号分别为1,2。每分钟有其中的一棵树会掉下一个苹果,奶牛一分钟只能在其中一棵树下接到苹果,但她不知道下一分钟会是那棵树掉下苹果,所以她就要在两棵树下来回跑。但她只会在树下跑W次。问你在T分钟内,奶牛bessie最多能接到多少苹果。

思路:一道简单的DP。

先给出状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+count。这里的dp[i][j]代表在第i分钟移动j次最多能接到的苹果数。

在第i分钟奶牛到某棵树下有两种状态:

1.从另一棵树走过来(dp[i-1][j-1])

2.本来就呆在这棵树下(dp[i-1][j])。所以在第i分钟时能接到的最大苹果数就是dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+count。

这里count的值可以这样计算:如果j为偶数说明她移动了j次又回到了第一棵树下,则count=a[i]==1?1:0;即count=2-a[i]。若j为奇数说明她移动了j次后到了第二棵树下,则count=a[i]==2?1:0(即count=a[i]-1)。

#include <iostream>
#include <cstdio>

using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1000 + 5;
const int INF = 0x3f3f3f3f;
typedef long long LL;
int s[maxn];
int dp[maxn][40];//p[i][j]代表第i棵树 最多j次走 最大能吃到的Apple
int solve (int t,int w)
{
   int count;
   for(int i=0;i <= w;i++) dp[0][i] = 0;//初始化

   for(int i =1;i <= t;i++)//一共最多w次
   {
       dp[i][0] = dp[i-1][0] + 2-s[i]; //如果一次没动过 只要s[i] = 1 就 +1
       for(int j=0;j <= w;j++)
       {
           if(j % 2) //j是奇数 此时在第2颗树上
                count =s[i] -1 ; //如果s[i] =2 说明有1次
           else //j是偶数 此时在第1颗树上
                count = 2-s[i];
           dp[i][j] = max(dp[i-1][j-1],dp[i-1][j]) + count;
       }
   }
   count = 0;
   for(int i=1;i <= t;i++){
    for(int j=0;j <= w ;j++){
        if(dp[i][j] > count )
            count = dp[i][j];
    }
   }
   return count;
}

int main()
{
    int t,w;
    scanf("%d %d",&t,&w);
    for(int i=1;i <= t;i++)
    {
        cin >> s[i];
    }
    cout<< solve(t,w)<<endl;
    return 0;
}

C

//其实第三题的 count不需要比较 因
//为递推的时候dp = max(dp[i-1][j] ,dp[i][j]) 了  就是现在的状态记录的已经是最优解
   count = 0;
   for(int i=1;i <= t;i++){
     for(int j=0;j <= w ;j++){
         if(dp[i][j] > count )
             count = dp[i][j];
     }
   }
   return count;
//所以这段可以 直接修改为  return dp[t][w];

c题补充

POJ3616Milking Time

题意:

在一个农场里,在长度为N个时间可以挤奶,但只能挤M次,且每挤一次就要休息t分钟;

接下来给m组数据表示挤奶的时间与奶量求最大挤奶量

思路:

每次 结束时间 += 休息的时间,接着按照 开始时间 排序

接着 状态转移方程 dp[i] = max(dp[i] , dp[j] + dp[i].cost) ( j > i && s[j].start >= s[i].end )

#include <iostream>
#include <algorithm>
using namespace std;
struct P{
    int left,ri,cost;
    bool operator < (const P & other)const
    {
        return (left < other.left||(left == other.left) &&ri < other.ri );
    }
}s[1010];

int dp[1010];

int main ()
{
    int n,m,t;
    cin >>n>>m>>t;
    for(int i=1;i<= m;i++){
        cin >> s[i].left>> s[i].ri >> s[i].cost;
        s[i].ri += t;
    }
    sort(s+1,s+1+m);
    for(int i=m; i ;i--)
    {
        dp[i] = s[i].cost;
        for(int j=i+1 ; j <= m;j++)
        {
            if(s[j].left >= s[i].ri)
            dp[i] = max(dp[i], dp[j] + s[i].cost);//状态转移方程
        }
    }
    int count = 0;
    for(int i=1;i <= m;i++)
        count = max(count ,dp[i]);
    cout<< count<<endl;
    return 0;
}

D

时间: 2024-11-06 08:27:31

dp入门 专题记录 2017-7-26的相关文章

树形dp 入门

今天学了树形dp,发现树形dp就是入门难一些,于是好心的我便立志要发一篇树形dp入门的博客了. 树形dp的概念什么的,相信大家都已经明白,这里就不再多说.直接上例题. 一.常规树形DP P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.所以

HDU 2084 数塔(简单DP入门)

数塔 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 41852    Accepted Submission(s): 24820 Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

[poj2342]Anniversary party树形dp入门

题意:选出不含直接上下司关系的最大价值. 解题关键:树形dp入门题,注意怎么找出根节点,运用了并查集的思想. 转移方程:dp[i][1]+=dp[j][0];/i是j的子树 dp[i][0]+=max(dp[j][0],dp[j][1]); 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<iostream> 6

团队作业4——第一次项目冲刺(Alpha版本)2017.4.26

2017.04.26 天气热. 时间:上午 9:35 ---10:10分 地点:陆大304实验室 会议内容:今天将昨天的的一些问题进行了讨论,以及针对助教提出的问题进行了分析,是因为我们昨天经过讨论后在任务中又加上了一些细节,导致了任务又多了一点点.随着时间的临近,项目Alpha版本即将截止,今天小组成员对任务有又进行了确认,齐心协力完成我们的任务. 1:每日讨论图片(拍摄者小组成员 黄睿) 2.任务分解图: 3.任务分配: 今天的整体分工如下: 武健男:负责今天的博客编写: 林俊鹏:询问实验室

数位DP入门题 hdu 2089 hdu 3555

hdu 2089 不要62 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意:对于每次给出的一个区间,找出区间内多少个数字没有出现62和4. 思路: 数位DP入门题,对于dfs设置3个参数. 一个表示现在进行到第几位, 一个表示前一个标记状态,这里表示上一位是不是6. 一个表示是否现在是这位可以取到的最大的数字. 如果上一位是6,那么这位不可以取2.且当前位都不可以取4. 1 #include <bits/stdc++.h> 2 us

POJ 3342 树形DP入门题

题目意思和POJ2342一样,只是多加了一个条件,如果最大方案数唯一,输出Yes,不唯一输出No dp的是时候多加一个变量记录答案是否唯一即可 #include "stdio.h" #include "string.h" #include "vector" using namespace std; struct node { int fa; vector<int>child; }data[210]; struct comp { int

POJ 1947 树形DP入门题

给出N个点,N-1个关系,建出树形图,问最少减去几个边能得到节点数为P的树.典型树形DP题 dp[cur][j] :记录cur结点,要得到一棵j个节点的子树去掉的最少边数 转移方程用的背包的思想 对当前树的每一个子树进行计算 砍掉此子树:   dp[cur][j]=dp[cur][j]+1; 不砍掉:           for (l=0;l<=j;l++)  dp[cur][j]=Min(dp[cur][j],dp[cur][l]+dp[next][j-l]); 枚举从该树中留l个节点其他由新

xbz分组题B 吉利数字 数位dp入门

B吉利数字时限:1s [题目描述]算卦大湿biboyouyun最近得出一个神奇的结论,如果一个数字,它的各个数位相加能够被10整除,则称它为吉利数.现在叫你计算某个区间内有多少个吉利数字. [输入]第一行为样例个数N.接下来N行,每一行代表一个输入样例,每个输入样例有2个数,分别代表某个区间的起点a和终点b.注意所求区间为[a,b],1<=a<=b<=10^9 [输出]N行.对于第x个输入样例,在第x行输入该样例所对应的结果. [输入样例]21 101 20 [输出样例]01 [Hint

dp入门题目

本文文旨,如题... 转载请注明出处... HDOJ 1176 免费馅饼 http://acm.hdu.edu.cn/showproblem.php?pid=1176 类似数塔,从底往上推,每次都是从下面三个中选最大的 1 #include<cstdio> 2 #include<cstring> 3 #define MAXN 100005 4 int dp[MAXN][11];//第i秒第j个位置的馅饼数 5 int max1(int a,int b) 6 { 7 return a