[DP训练]rqnOJ

P188 购物问题

题目梗概:

n个物品,其中每个物品价格xi,但是某两个物品不能同时购买。

问最大的价格是多少?

思考与理解:

一开始并没有想到树形背包DP,只是一直在想是不是分组背包~

在之后瞅了瞅题解的思路之后,恍然大悟。

先把有限制的物品之间的关系转换为父子关系就可以进行DP了。

对于每个有限制的物品要不选 要么不选 选的话会有什么结果 不选的话有什么结果。

如果没有限制的话 那么肯定是要买的~

#include <cstdio>
#include <algorithm>
#include <cstring>
#define up(a,b,c) for(register int c=a;c<=b;++c)
int n,m;
int dp[1005][3];
int maodun[1005][1005],value[1005],ans,son[1005][1005];
bool used[1005];

void dfs(int x){
    used[x] = true;
    up(1,maodun[x][0],i){
        if(!used[maodun[x][i]]){
            son[x][++son[x][0]] = maodun[x][i];
            dfs(maodun[x][i]);
        }
    }
}

void RunDp(int x){
    if(son[x][0]==0){
        dp[x][1]=value[x];
        dp[x][0]=0;
    }
    else{
        up(1,son[x][0],i) RunDp(son[x][i]);
        up(1,son[x][0],i){
            int v = son[x][i];
            dp[x][1]+=dp[v][2];
            dp[x][2]+=std::max(dp[v][1],dp[v][2]);
        }
        dp[x][1]+=value[x];
    }
}

int main(){
    scanf("%d%d",&n,&m);
    up(1,n,i) scanf("%d",&value[i]);
    up(1,m,i){
        int x,y;
        scanf("%d%d",&x,&y);
        maodun[x][++maodun[x][0]] = y;
        maodun[y][++maodun[y][0]] = x;
    }
    up(1,n,i){
        if(maodun[i][0]==0){
            ans+=value[i];
            used[i] = 1;
        }
        else{
            if(!used[i]){
                dfs(i);
                RunDp(i);
                ans+=std::max(dp[i][1],dp[i][2]);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

P188

P201 奥运大包围

题目梗概:

(题面什么鬼)问题就是求一个环从某个地方断开,然后求LIS,取LIS最小值即可.

思考:

LIS挺简单的,但必须用nlogn的二分做法,否则n^3会TLE。

#include<string.h>
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[10001];
int num[10001];
int a[20001];
int nums;
int ans;
void cha(int x)
{
    if(nums==0||x>=num[nums-1])
    {
        num[nums++]=x;
        return ;
    }
    int l,r,mid;
    l=0,r=nums;
    mid=(l+r)/2;
    while(l<r)
    {
        if(num[mid]<=x)l=mid+1;
        else if(num[mid]>x) r=mid;
        mid=(l+r)/2;
    }
    num[mid]=x;
}
void dos(int l,int r)
{
    nums=0;
    for(int i=l; i<r; i++)
    {
        cha(a[i]);
    }
    ans=min(ans,nums);
}
int main()
{
    int n,i;
    scanf("%d",&n);
    ans=n;
    for(i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
    }
    for(i=n; i<2*n; i++)
    {
        a[i]=a[i-n];
    }
    for(i=0; i<n; i++)
    {
        dos(i,i+n);
    }
    cout<<ans<<endl;
    return 0;
}  

P201

P202 奥运火炬登珠峰

题面梗概:

n个物品,每个物品都有一个x氧气含量,y氮气含量,z重量。

给出保障生命安全的a,b,问z的最小重量是多少。

思考:

普通的一个二位费用背包,没啥说的。只不过需要把上限a,b开大点。毕竟选的x,y可以超过这个下限a,b

#include <cstdio>
#include <algorithm>
#include <cstring>

int dp[233][1005];
int A,T,n;
int O[1005],N[1005],G[1005];
int Out=0x3f3f3f3f;

int main(){
    memset(dp,0x3f3f3f3f,sizeof(dp));
    scanf("%d%d",&A,&T);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d%d",&O[i],&N[i],&G[i]);
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=A+A;j>=O[i];j--){
            for(int k=T+T;k>=N[i];k--){
                dp[j][k]=std::min(dp[j][k],dp[j-O[i]][k-N[i]]+G[i]);
                //Out=std::min(Out,dp[j][k]);
            }
        }
    }
    for(int i=A+A;i>=A;i--){
        for(int j=T+T;j>=T;j--){
            Out=std::min(Out,dp[i][j]);
            //if(dp[i][j]==129) printf("%d %d\n",i,j);
        }
    }

    printf("%d\n",Out);
    return 0;
}

P202

P671 纯洁的买卖

题面梗概:

猪脚有m元经费,他会以x买入某件物品,以y的价格卖出。问最后会有多少钱。

思考:

背包问题,只不过需要处理一下xy的关系。

#include <cstdio>
#include <algorithm>
#include <cstring>

int n,m;
int dp[1000005];
int x,y;

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x,&y);
        y-=x*2;
        for(int j=x;j<=m;j++){
            if(j-x>=0)dp[j]=std::max(dp[j],dp[j-x]+y);
            //printf("dp[%d]:%d\n",j,dp[j]);
        }
    }
    printf("%d\n",dp[m]+m);
    return 0;
}

P671

P57 找啊找啊找GF

题面梗概:

n个MM,每个MM需要花费rmb,rp,time,猪脚有m块RMB,r的人品值。

在保证MM数量的前提下,最小花费时间是多少。

思考:

一开始想着只用一个二维费用背包搞,记录MM数量最大是多少,然后在这个数量中查找一个最小值时间。

但是发现莫名其妙WA了,看了看题解。

发现做法很妙:

如果MM数量多,就保留多的。

如果MM数量一样,那么久保留时间短的。

#include <cstdio>
#include <cstring>
#include <algorithm>

int n,m,r;
int dp[105][105];
int TIME[105][105];
int x[105],y[105],z[105];
int Min=0x3f3f3f3f;

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&x[i],&y[i],&z[i]);
    }
    scanf("%d%d",&m,&r);
    for(int i=1;i<=n;i++){
        for(int j=m;j>=x[i];j--){
            for(int k=r;k>=y[i];k--){
                if(dp[j][k] < dp[j-x[i]][k-y[i]]+1){
                dp[j][k] = dp[j-x[i]][k-y[i]]+1;
                TIME[j][k] = TIME[j-x[i]][k-y[i]]+z[i];
                }
                if(dp[j][k] == dp[j-x[i]][k-y[i]]+1 && TIME[j][k] > TIME[j-x[i]][k-y[i]]+z[i]){
                TIME[j][k] = TIME[j-x[i]][k-y[i]]+z[i];
                }
                //printf("dp[%d][%d]:%d\n",j,k,dp[j][k]);
            }
        }
    }
    printf("%d",TIME[m][r]);
    return 0;
}

p57

P140 分配时间

题面梗概:

n个科目,t时间。

每个科目花费不同的时间可以得到不同的分数,但每门科目需要之前写名字花费x时间。

问最多可以拿到几分?

思考:

分组背包,只不过需要特出处理一下写名字的时间。

#include <cstdio>
#include <algorithm>
#include <cstring>

int T,n,name;
int num[23][233];
int dp[233333];

int main(){
    scanf("%d%d%d",&T,&n,&name);
    //读入
    for(int i=1;i<=n;i++){
        for(int j=1;j<=T;j++){
            scanf("%d",&num[i][j+name]);
        }
    }

    for(int k=1;k<=n;k++){
        for(int i=T;i>=name;i--){
            for(int j=i;j>=name;j--){
                dp[i] = std::max(dp[i],dp[i-j]+num[k][j]);
            }
        }
    }

    printf("%d\n",dp[T]);
    return 0;
} 

P140

P169 最小乘车费用

题面梗概:

每个车最多可以行驶10公里,行驶1,2,3,4...10公里的费用各不相同。

问行驶x公里的,最小费用是多少。

思考:

背包问题.

#include <cstdio>
#include <algorithm>
#include <cstring>

int n,num[105];
int dp[233];

int main(){
    memset(dp,0x3f3f3f3f,sizeof(dp));
    for(int i=1;i<=10;i++) scanf("%d",&num[i]),dp[i]=num[i];
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=10;j++){
            if(i>j) dp[i]=std::min(dp[i],dp[i-j]+num[j]);
            else break;
            //printf("dp[%d]:%d\n",i,dp[i]);
        }
    }
    printf("%d\n",dp[n]);
    return 0;
}

P169

P95 多多看DV(加强版)

题面梗概:

爷爷给出T单位时间,商店有n个碟片,叔叔必须买m个(不能多不能少),输入的每个碟片会花费x的时间,会得到y的快乐。

如果碟片没法在规定时间内看完输出0,否则输出今晚的总分.

思考:

题面需要转化一下,把时间当作一个物品属性。进行二维费用背包。

贪心的思考一下:如果n个物品中,m个物品的时间>T的话。直接输出0

#include <cstdio>
#include <algorithm>
#include <cstring>

int n,limit,l;
int t[105],m[105],fuck[105],Can[105];
int dp[233333][233];

int main(){
    memset(dp,-0x3f3f3f3f,sizeof(dp));
    scanf("%d%d%d",&n,&limit,&l);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&t[i],&m[i]);
        Can[i]=t[i];
        fuck[i]=1;
    }
    std::sort(Can+1,Can+1+n);
    int ans=0;
    for(int i=1;i<=limit;i++){
        ans+=Can[i];
    }
    if(ans>l){
        printf("0\n");
        return 0;
    }
    for(int i=0;i<=l;i++) dp[i][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=l;j>=t[i];j--){
            for(int k=limit;k>=1;k--){
                dp[j][k] = std::max(dp[j][k],dp[j-t[i]][k-1]+m[i]);
            }
        }
    }
    printf("%d\n",dp[l][limit]);
    return 0;
}

P95

时间: 2024-12-12 07:12:19

[DP训练]rqnOJ的相关文章

HDU dp训练

1. 1003 最大和连续子序列 状态方程:dp[i]=max(dp[j-1]+num[i],num[i]); 解:存放dp数组每个元素都是从左至右最大连续子序列的值,即dp[i]为从0-i处最大连续子序列的值 注意边界 1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 using namespace std; 5 #define N 100005 6 int dp[N]; 7 int a[

RQNOJ 342 最不听话的机器人:网格dp

题目链接:https://www.rqnoj.cn/problem/342 题意: DD 有一个不太听话的机器人,这个机器人总是会有自己的想法,而不会完全遵守 DD 给它的指令. 现在 DD 在试图命令机器人走迷宫.迷宫是一个 N*N 个格子组成的区域,格子自左上角到右下角从 (1,1) 到 (N,N) 编号.第 i 行.第 j 列的格子编号为 (i,j).迷宫中的某些区域是障碍物,机器人不能移动到那里. DD 给了机器人 M 条指令,指令的类型包括"前进一步""后退一步&q

RQNOJ 622 最小重量机器设计问题:dp

题目链接:https://www.rqnoj.cn/problem/622 题意: 一个机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得. w[i][j]是从供应商j处购得的部件i的重量,c[i][j] 是相应的价格. 试设计一个算法,给出总价格不超过d的最小重量机器设计. 题解: 表示状态: dp[i][j] = min weight i:考虑到第i个零件 j:当前花费 找出答案: min dp[n][j] (0<=j<=d) 如何转移: 对于当前零件i,枚举不同的供应商j,转移

ACM/ICPC算法训练 之 数学很重要-浅谈“排列计数” (DP题-POJ1037)

这一题是最近在看Coursera的<算法与设计>的公开课时看到的一道较难的DP例题,之所以写下来,一方面是因为DP的状态我想了很久才想明白,所以借此记录,另一方面是看到这一题有运用到 排列计数 的方法,虽然排列计数的思路简单,但却是算法中一个数学优化的点睛之笔. Poj1037  A decorative fence 题意:有K组数据(1~100),每组数据给出总木棒数N(1~20)和一个排列数C(64位整型范围内),N个木棒长度各异,按照以下条件排列,并将所有可能结果进行字典序排序 1.每一

RQNOJ 311 [NOIP2000]乘积最大:划分型dp

题目链接:https://www.rqnoj.cn/problem/311 题意: 给你一个长度为n的数字,用t个乘号分开,问你分开后乘积最大为多少.(6<=n<=40,1<=k<=30) 题解: 简化问题: 给原数字之前添加一个"1 *",乘号不计入数量,对答案无影响. 例如:"1231"可以变成"(1*)1231". 表示状态: dp[i][j] = max num(最后一个乘号之前的最大乘积) i:此时在第i个数的前

RQNOJ 328 炮兵阵地:状压dp

题目链接:https://www.rqnoj.cn/problem/328 题意: 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队. 一个N*M的地图由N行M列组成(N≤100,M≤10),地图的每一格可能是山地(用'H' 表示),也可能是平原(用'P'表示),如下图. 在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队): 一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:

RQNOJ 514 字串距离:dp &amp; 字符串

题目链接:https://www.rqnoj.cn/problem/514 题意: 设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为"abcbcd",则字符串"abcb_cd","_a_bcbcd_"和"abcb_cd_"都是X的扩展串,这里"_"代表空格字符. 如果A1是字符串A的扩展串,B1是字符串B的扩展串,A1与B1具有相同的长度,那么我扪定义字符串A1

RQNOJ 188 购物问题:树形dp

题目链接:https://www.rqnoj.cn/problem/188 题意: 商场以超低价格出售n个商品,购买第i个商品所节省的金额为w[i]. 为了防止亏本,有m对商品是不能同时买的.但保证商品关系不出现环,不会出现如:(1,2) , (2,4) , (1,4). 问你最多能节省的金额. 题解: 简直和POJ 2342 Anniversary party像极了(*/ω\*) 将不能同时买的商品间连一条无向边. 所以子节点和父节点不能同时选. 唯一不同的是POJ是一棵树,而这道题是一片森林

RQNOJ 169 最小乘车费用:水dp

题目链接:https://www.rqnoj.cn/problem/169 题意: 给出行驶1-10公里的费用(所有车一样),可以倒车,问行驶n公里的最小费用. 题解: 大水题... (=′ω`=) 表示状态: dp[i] = min cost i:行驶了i公里 找出答案: ans = dp[n] 如何转移: now: dp[i] dp[i+j] = min dp[i] + c[j] 枚举倒车行驶j公里 边界条件: dp[0] = 0 others = -1 AC Code: 1 // stat