多维动态规划 (共六题)
来源:互联网 发布:淘宝网的域名怎么设置 编辑:程序博客网 时间:2024/05/22 06:33
这六道题难度依次递升
P1508 Likecloud-吃、吃、吃
URL: https://www.luogu.org/problem/show?pid=1508#sub
题目背景
问世间,青春期为何物?
答曰:“甲亢,甲亢,再甲亢;挨饿,挨饿,再挨饿!”
题目描述
正处在某一特定时期之中的李大水牛由于消化系统比较发达,最近一直处在饥饿的状态中。某日上课,正当他饿得头昏眼花之时,眼前突然闪现出了一个n*m(n and m<=200)的矩型的巨型大餐桌,而自己正处在这个大餐桌的一侧的中点下边。餐桌被划分为了n*m个小方格,每一个方格中都有一个圆形的巨型大餐盘,上面盛满了令李大水牛朝思暮想的食物。李大水牛已将餐桌上所有的食物按其所能提供的能量打了分(有些是负的,因为吃了要拉肚子),他决定从自己所处的位置吃到餐桌的另一侧,但他吃东西有一个习惯——只吃自己前方或左前方或右前方的盘中的食物。
由于李大水牛已饿得不想动脑了,而他又想获得最大的能量,因此,他将这个问题交给了你。
每组数据的出发点都是最后一行的中间位置的下方!
输入输出格式
输入格式:
[输入数据:]
第一行为m n.(n为奇数),李大水牛一开始在最后一行的中间的下方
接下来为m*n的数字距阵.
共有m行,每行n个数字.数字间用空格隔开.代表该格子上的盘中的食物所能提供的能量.
数字全是整数.
输出格式:
[输出数据:]
一个数,为你所找出的最大能量值.
输入输出样例
输入样例#1:
6 7
16 4 3 12 6 0 3
4 -5 6 7 0 0 2
6 0 -1 -2 3 6 8
5 3 4 0 0 -2 7
-1 7 4 0 7 -5 6
0 -1 3 4 12 4 2
输出样例#1:
41
说明
快吃!快吃!快吃!
水题
#include<stdio.h>const int MAXN=2e2+5;int arr[MAXN][MAXN],dp[2][MAXN],n,m;int max(int a,int b,int c){ int t=a>b?a:b; return t>c?t:c;}int main(){ scanf("%d%d",&m,&n); for(int i=0;i<m;++i){ for(int j=1;j<=n;++j){ scanf("%lld",&arr[i][j]); } } for(int i=0;i<=n+1;++i) dp[0][i]=dp[1][i]=-1e9; dp[m&1][n/2+1]=0; int ans=0; for(int i=m-1;i>=0;--i){ for(int j=1;j<=n;++j){ dp[i&1][j]=max(dp[~i&1][j],dp[~i&1][j-1],dp[~i&1][j+1])+arr[i][j]; } } for(int i=1;i<=n;++i) if(dp[0][i]>ans) ans=dp[0][i]; printf("%lld\n",ans); return 0;}
P1387 最大正方形
URL: https://www.luogu.org/problem/show?pid=1387#sub
题目描述
在一个n*m的只包含0和1的矩阵里找出一个不包含0的最大正方形,输出边长。
输入输出格式
输入格式:
输入文件第一行为两个整数n,m(1<=n,m<=100),接下来n行,每行m个数字,用空格隔开,0或1.
输出格式:
一个整数,最大正方形的边长
输入输出样例
输入样例#1:
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1
输出样例#1:
2
xjb暴力即可
#include<stdio.h>#include<algorithm>using namespace std;const int MAXN=1e2+2;int arr[MAXN][MAXN],sum[MAXN][MAXN],n,m; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ scanf("%d",&arr[i][j]); sum[i][j]=sum[i][j-1]+arr[i][j]; } } int a=0; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ int k=j; while(arr[i][k]) ++k; --k; int d=k-i+1; for(int u=0;u+i<=n&&!(k<j||k-j<u);++u){ while(k>=j&&sum[u+i][k]-sum[u+i][j-1]!=k-j+1) --k; // printf("[%d %d] %d ---> %d\n",i,j,u,k); a=max(a,min(u+1,k+1-j)); } } } printf("%d\n",a); return 0;}
P1855 榨取kkksc03
URL: https://www.luogu.org/problem/show?pid=1855#sub
题目描述
Kkksc03的时间和金钱是有限的,所以他很难满足所有同学的愿望。所以他想知道在自己的能力范围内,最多可以完成多少同学的愿望?
输入输出格式
输入格式:
第一行,n M T,表示一共有n(n<=100)个愿望,kkksc03 的手上还剩M(M<=200)元,他的暑假有T(T<=200)分钟时间。
第2~n+1行 mi,ti 表示第i个愿望所需要的时间和金钱。
输出格式:
一行,一个数,表示kkksc03最多可以实现愿望的个数。
输入输出样例
输入样例#1:
6 10 10
1 1
2 3
3 2
2 5
5 2
4 3
输出样例#1:
4
说明
提示 第1,2,3,6个
#include<stdio.h>const int MAXN=202;int dp[MAXN][MAXN],n,M,T;int max(int a,int b){return a>b?a:b;}int main(){ scanf("%d%d%d",&n,&M,&T); for(int i=0;i<n;++i){ int w,v; scanf("%d%d",&w,&v); for(int t=T;t>=w;--t){ for(int m=M;m>=v;--m){ dp[t][m]=max(dp[t][m],dp[t-w][m-v]+1); } } } int ans=0; for(int i=0;i<=T;++i) for(int j=0;j<=M;++j) ans=max(ans,dp[i][j]); printf("%d\n",ans); return 0;}
P1736 创意吃鱼法
URL: https://www.luogu.org/problem/show?pid=1736#sub
题目描述
回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中,然后开始思考:到底要以何种方法吃鱼呢(猫猫就是这么可爱,吃鱼也要想好吃法 ^_*)。她发现,把大池子视为01矩阵(0表示对应位置无鱼,1表示对应位置有鱼)有助于决定吃鱼策略。
在代表池子的01矩阵中,有很多的正方形子矩阵,如果某个正方形子矩阵的某条对角线上都有鱼,且此正方形子矩阵的其他地方无鱼,猫猫就可以从这个正方形子矩阵“对角线的一端”下口,只一吸,就能把对角线上的那一队鲜鱼吸入口中。
猫猫是个贪婪的家伙,所以她想一口吃掉尽量多的鱼。请你帮猫猫计算一下,她一口下去,最多可以吃掉多少条鱼?
输入输出格式
输入格式:
有多组输入数据,每组数据:
第一行有两个整数n和m(n,m≥1),描述池塘规模。接下来的n行,每行有m个数字(非“0”即“1”)。每两个数字之间用空格隔开。
对于30%的数据,有n,m≤100
对于60%的数据,有n,m≤1000
对于100%的数据,有n,m≤2500
输出格式:
只有一个整数——猫猫一口下去可以吃掉的鱼的数量,占一行,行末有回车。
输入输出样例
输入样例#1:
4 6
0 1 0 1 0 0
0 0 1 0 1 0
1 1 0 0 0 1
0 1 1 0 1 0
输出样例#1:
3
说明
右上角的
1 0 0 0 1 0 0 0 1
题解
这是一道比较麻烦的题,我压缩代码了,不然可能会长很多。复杂度
我们可以记录斜着的1连续长度
由于判断的逻辑可以优化到o(1),那么整体复杂度就是
#include<stdio.h>const int MAXN=2505;int dp[2][2][MAXN],zore[MAXN],arr[MAXN],n,m;int max(int a,int b){return a>b?a:b;}int min(int a,int b,int c){ int t=a<b?a:b; return t<c?t:c;}int main(){ scanf("%d%d",&n,&m); int ans=0; for(int i=1;i<=n;++i){ for(int j=1,l=0;j<=m;++j){ scanf("%d",&arr[j]); int t=arr[j]; dp[i&1][0][j]=t*(dp[~i&1][0][j-1]+1); dp[i&1][0][j]=min(dp[i&1][0][j],zore[j]+1,l+1); l=(1-t)*(l+1); ans=max(ans,dp[i&1][0][j]); } for(int j=m,l=0;j>0;--j){ int t=arr[j]; dp[i&1][1][j]=t*(dp[~i&1][1][j+1]+1); dp[i&1][1][j]=min(dp[i&1][1][j],zore[j]+1,l+1); l=(1-t)*(l+1); ans=max(ans,dp[i&1][1][j]); zore[j]=(1-t)*(zore[j]+1); } } printf("%d\n",ans); return 0;}
P1006 传纸条
URL :https://www.luogu.org/problem/show?pid=1006
题目描述
小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。
在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。
还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。
输入输出格式
输入格式:
输入文件message.in的第一行有2个用空格隔开的整数m和n,表示班里有m行n列(1<=m,n<=50)。
接下来的m行是一个m*n的矩阵,矩阵中第i行j列的整数表示坐在第i行j列的学生的好心程度。每行的n个整数之间用空格隔开。
输出格式:
输出文件message.out共一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。
输入输出样例
输入样例#1:
3 3
0 3 9
2 8 5
5 7 0
输出样例#1:
34
说明
【限制】
30%的数据满足:1<=m,n<=10
100%的数据满足:1<=m,n<=50
NOIP 2008提高组第三题
题解
以起点出发到终点同时走,dp[x1][y1][x2][y2] 表示走到(x1,y1) ,(x2,y2) 时的值
由于 x1+y1=x2+y2=Step 所以dp可以压缩一维用dp[setp][x1][x2] 表示
转移方程就是从能走到 (x1,y1) ,(x2,y2) 的方案中选取最优的
#include<stdio.h>const int MAXN=105;int dp[MAXN<<1][MAXN][MAXN],arr[MAXN][MAXN],n,m;int max(int a,int b,int c,int d){ a=a>b?a:b; a=a>c?a:c; return a>d?a:d;}int main(){ scanf("%d%d",&m,&n); for(int i=1;i<=m;++i){ for(int j=1;j<=n;++j){ scanf("%d",&arr[i][j]); } } dp[1][1][1]=arr[1][1]; for(int step=1;step<=n+m;++step){ for(int x1=1;x1<=n;++x1) for(int x2=1;x2<=n;++x2){ if(x1==x2) continue; dp[step][x1][x2]=arr[step-x1][x1]+arr[step-x2][x2]+ max(dp[step-1][x1][x2], dp[step-1][x1-1][x2], dp[step-1][x1][x2-1], dp[step-1][x1-1][x2-1]); } } int ans=max(dp[n+m][n][n],dp[n+m][n-1][n],dp[n+m][n][n-1],dp[n+m][n-1][n-1])+arr[m][n]; printf("%d\n",ans); return 0;}
P1417 烹调方案
URL: https://www.luogu.org/problem/show?pid=1417#sub
题目背景
由于你的帮助,火星只遭受了最小的损失。但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星。不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~
gw还是会做饭的,于是拿出了储藏的食物准备填饱肚子。gw希望能在T时间内做出最美味的食物,但是这些食物美味程度的计算方式比较奇葩,于是绝望的gw只好求助于你了。
题目描述
一共有n件食材,每件食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去ci的时间。
众所周知,gw的厨艺不怎么样,所以他需要你设计烹调方案使得美味指数最大
输入输出格式
输入格式:
第一行是两个正整数T和n,表示到达地球所需时间和食材个数。
下面一行n个整数,ai
下面一行n个整数,bi
下面一行n个整数,ci
输出格式:
输出最大美味指数
输入输出样例
输入样例#1:
74 1
502
2
47
输出样例#1:
408
说明
【数据范围】
对于40%的数据1<=n<=10
对于100%的数据1<=n<=50
所有数字均小于100,000
【题目来源】
tinylic改编
题解
01背包的升级,让性价比最高的先排
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int MAXN=105;const int MAXT=1e6+5;long long dp[MAXT];int T,n;struct node{long long a,b,c;}dat[MAXN];bool cmp(node x,node y){return x.b*y.c>y.b*x.c;}int main(){ scanf("%d%d",&T,&n); for(int i=0;i<n;++i) scanf("%lld",&dat[i].a); for(int i=0;i<n;++i) scanf("%lld",&dat[i].b); for(int i=0;i<n;++i) scanf("%lld",&dat[i].c); sort(dat,dat+n,cmp); long long time=0; memset(dp,-0x3f,sizeof(dp)); const long long INF=dp[0]; dp[0]=0; for(int i=0;i<n;++i){ for(int j=T;j>=dat[i].c;--j){ if(dp[j-dat[i].c]>INF) dp[j]=max(dp[j],dp[j-dat[i].c]+dat[i].a-j*dat[i].b); } } long long ans=0; for(int i=1;i<=T;++i) ans=max(ans,dp[i]); printf("%lld\n",ans); return 0;}
- 多维动态规划 (共六题)
- 找啊找啊找GF (多维动态规划)
- 洛谷 1387——最大正方形(多维动态规划)
- 洛谷-多维动态规划-传纸条
- 洛谷 1508——Likecloud-吃、吃、吃(多维动态规划)
- GF-动态规划dp-多维费用的背包
- 洛谷Oj-Likecloud-吃、吃、吃-多维动态规划
- 多维动态规划——洛谷P1006 传纸条
- 线性动态规划 (共六题)
- 【动态规划(一)】动态规划基础
- 动态规划(1)
- 动态规划(2)
- 动态规划(3)
- 动态规划(4)
- HDOJ2046(动态规划)
- 动态规划(one)
- 动态规划(读书笔记)
- Pearls(动态规划)
- 1055. The World's Richest (25)
- 将需要人为触发的事件放在定时器或者循环中,程序有可能产生Bug
- POI操作Excel
- 【玩转Eclipse】——eclipse实现代码块自定义折叠---[类似于VS中的#region……#endregion]
- 《剑指offer》笔记-第4章(2)
- 多维动态规划 (共六题)
- BZOJ4216【Pig】
- Android实现照相机拍照
- Java中的堆和栈
- 侧边悬浮框
- Linux问题—设置“进程最大可打开的文件数”永久有效的方式
- 下列有关静态成员函数的描述中,正确的是:
- php+html 表单提交数据保存到mysql中
- Mybatis Generator的model生成中文注释,支持oracle和mysql(通过修改源码的方式来实现)