2016.4.9 NOI codevs动态规划专练
1.NOI 最大子矩阵
1:最大子矩阵
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
- 已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。
比如,如下4 * 4的矩阵
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2的最大子矩阵是
9 2
-4 1
-1 8这个子矩阵的大小是15。
- 输入
- 输入是一个N * N的矩阵。输入的第一行给出N (0 < N <= 100)。再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。已知矩阵中整数的范围都在[-127, 127]。
- 输出
- 输出最大子矩阵的大小。
- 样例输入
-
4
0 -2 -7 0 9 2 -6 2
-4 1 -4 1 -1 8 0 -2 - 样例输出
-
15
- 来源
- 翻译自 Greater New York 2001 的试题
- 一般做法:N^3时间复杂度
/*方法:枚举每一行所有的区间情况,把这个区间从第一列向下加,加的过程中注意:因为有负数,所以如果之前加的和<0了,我们要舍弃之前的所有结果,重新开始新的矩阵,而且要注意对于ans的更新是在加的过程更新,因为随时有可能加上负数,虽然sum>0,所以加一次都要更新*/
#include<iostream>
using namespace std;
#include<cstdio>
const int N=;
const int INF=<<;
int n,a[N][N];
int main()
{
scanf("%d",&n);
int x;
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
{
scanf("%d",&x);
a[i][j]=a[i][j-]+x;
}
int ans=-INF;
for(int i=;i<=n;++i)
for(int j=i;j<=n;++j)
{
int tmp=;
for(int k=;k<=n;++k)
{
int num=a[k][j]-a[k][i-];
if(tmp>) tmp+=num;
else tmp=num;
if(tmp>ans) ans=tmp;
}
}
printf("%d\n",ans);
return ;
}
2.NOI 6047:分蛋糕
6047:分蛋糕
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
有一块矩形大蛋糕,长和宽分别是整数w 、h。现要将其切成m块小蛋糕,每个小蛋糕都必须是矩形、且长和宽均为整数。切蛋糕时,每次切一块蛋糕,将其分成两个矩形蛋糕。请计算:最后得到的m块小蛋糕中,最大的那块蛋糕的面积下限。
假设w= 4, h= 4, m= 4,则下面的切法可使得其中最大蛋糕块的面积最小。
假设w= 4, h= 4, m= 3,则下面的切法会使得其中最大蛋糕块的面积最小:
- 输入
- 共有多行,每行表示一个测试案例。每行是三个用空格分开的整数w, h, m ,其中1 ≤ w, h, m ≤ 20 , m ≤ wh. 当 w = h = m = 0 时不需要处理,表示输入结束。
- 输出
- 每个测试案例的结果占一行,输出一个整数,表示最大蛋糕块的面积下限。
- 样例输入
-
4 4 4
4 4 3
0 0 0 - 样例输出
- 4
- 6
- 代码:
/*这个题和之前做的那个棋盘分割很像,但是又有些不同,棋盘分割要求确定每一个矩形。
而在这个题目中,只要矩形的长宽还有切割的次数确定了,无论这个面积的矩形位于大矩形的什么地方,结果都是相同的,那就没有必要固定矩形位置,仅仅固定矩形的大小就可以了
第一次做,我用的就是确定矩形的位置,开了一个五维数组,结果全部超时,虽然样例过了。
f[i][j][k]表示的是i*j这个矩形分割为k份的最大面积的下限。
*/
#include<iostream>
using namespace std;
#include<cstdio>
#define N 21
int f[N][N][N];
int n,m,k;
#include<cstring>
void DP()
{
/*第一次的超时做法*/
/*for(int kk=1;kk<=k;++kk)
for(int x1=0;x1<=n;++x1)
for(int y1=0;y1<=m;++y1)
for(int x2=x1+1;x2<=n;++x2)
for(int y2=y1+1;y2<=m;++y2)
{
if(f[x1][y1][x2][y2][kk]<5000)
continue;
if(kk==1)
{
f[x1][y1][x2][y2][kk]=(x2-x1)*(y2-y1);
continue;
}
for(int x=x1+1;x<x2;++x)
{
f[x1][y1][x2][y2][kk]=min(max(f[x1][y1][x][y2][1],f[x][y1][x2][y2][kk-1]),f[x1][y1][x2][y2][kk]);
f[x1][y1][x2][y2][kk]=min(max(f[x1][y1][x][y2][kk-1],f[x][y1][x2][y2][1]),f[x1][y1][x2][y2][kk]);
}
for(int y=y1+1;y<y2;++y)
{
f[x1][y1][x2][y2][kk]=min(max(f[x1][y1][x2][y][1],f[x1][y][x2][y2][kk-1]),f[x1][y1][x2][y2][kk]);
f[x1][y1][x2][y2][kk]=min(max(f[x1][y1][x2][y][kk-1],f[x1][y][x2][y2][1]),f[x1][y1][x2][y2][kk]);
}
}*/ for(int kk=;kk<=k;++kk)
for(int x1=;x1<=n;++x1)
for(int y1=;y1<=m;++y1)
{
if(f[x1][y1][kk]<)/*记忆化搜索因为输入有多组数据,而且只要i,j,k确定,结果就不变,所以没有必要重复计算*/
continue;
if(kk==)
{
f[x1][y1][kk]=x1*y1;/*DP的初始化*/
continue;
}
for(int x=;x<x1;++x)
{
/* f[x1][y1][kk]=min(max(f[x][y1][kk-1],(x1-x)*y1),f[x1][y1][kk]);*/
/*f[x1][y1][kk]=min(max(x*y1,f[x1-x][y1][kk-1]),f[x1][y1][kk]);*/
for(int p=;p<kk;p++)
f[x1][y1][kk]=min(f[x1][y1][kk],max(f[x][y1][p],f[x1-x][y1][kk-p]));
/*这里与棋盘分割的不同,棋盘分割是上面的方程,因为棋盘分割要求“将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,”,所以必须是一块k-1份,一块1份才可以,
而这个“分蛋糕”只要求蛋糕是矩形,没要求每切一份,剩下的也是矩形*/
}
for(int y=;y<y1;++y)
{
/*f[x1][y1][kk]=min(max(f[x1][y][kk-1],x1*(y1-y)),f[x1][y1][kk]);*/
/* f[x1][y1][kk]=min(max(x1*y,f[x1][y1-y][kk-1]),f[x1][y1][kk]);*/
for(int p=;p<kk;p++)
f[x1][y1][kk]=min(f[x1][y1][kk],max(f[x1][y][p],f[x1][y1-y][kk-p]));
}
} }
int main()
{
memset(f,,sizeof(f));
while(scanf("%d%d%d",&n,&m,&k)==&&n&&m&&k)
{
DP();
printf("%d\n",f[n][m][k]);
}
return ;
}
3. NOI 6049:买书
6049:买书
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
小明手里有n元钱全部用来买书,书的价格为10元,20元,50元,100元。
问小明有多少种买书方案?(每种书可购买多本)
- 输入
- 一个整数 n,代表总共钱数。(0 <= n <= 1000)
- 输出
- 一个整数,代表选择方案种数
- 样例输入
-
样例输入1:
20 样例输入2:
15 样例输入3:
0 - 样例输出
-
样例输出1:
2 样例输出2:
0 样例输出3:
0
/*变形版的“线段覆盖”,把餐馆向后扩展k长度,作为一个线段就可以了*/
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#define N 101
int t,n,k,f[N];
struct Poi{
int l,r,val;
// bool operator <(const Poi &a)
// const { return r<a.r;}
};
Poi poi[N];
#include<algorithm>
void input()
{
memset(f,,sizeof(f));
memset(poi,,sizeof(poi));
scanf("%d%d",&n,&k);
for(int i=;i<=n;++i)
{
scanf("%d",&poi[i].l);
poi[i].r=poi[i].l+k;
}
for(int i=;i<=n;++i)
scanf("%d",&poi[i].val);
}
int ans=;
void DP()
{ // sort(poi+1,poi+n+1);
for(int i=;i<=n;++i)
f[i]=poi[i].val;
for(int i=;i<=n;++i)
{
for(int j=;j<i;++j)
{
if(poi[i].l>poi[j].r)
f[i]=max(f[i],f[j]+poi[i].val);
} }
}
int main()
{
scanf("%d",&t);
while(t--)
{
input();
DP();
ans=;
for(int i=;i<=n;++i)
ans=max(ans,f[i]);/*一开始犯了一个非常傻逼的错误,在DP中寻找f[i]的最大值,结果漏了f[1]恰好输入的数据有的就是仅仅建立第一个餐馆的利润最大,结果WA了*/
printf("%d\n",ans);
}
return ;
}
4978:宠物小精灵之收服
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
宠物小精灵是一部讲述小智和他的搭档皮卡丘一起冒险的故事。
一天,小智和皮卡丘来到了小精灵狩猎场,里面有很多珍贵的野生宠物小精灵。小智也想收服其中的一些小精灵。然而,野生的小精灵并不那么容易被收服。对于每一个野生小精灵而言,小智可能需要使用很多个精灵球才能收服它,而在收服过程中,野生小精灵也会对皮卡丘造成一定的伤害(从而减少皮卡丘的体力)。当皮卡丘的体力小于等于0时,小智就必须结束狩猎(因为他需要给皮卡丘疗伤),而使得皮卡丘体力小于等于0的野生小精灵也不会被小智收服。当小智的精灵球用完时,狩猎也宣告结束。
我们假设小智遇到野生小精灵时有两个选择:收服它,或者离开它。如果小智选择了收服,那么一定会扔出能够收服该小精灵的精灵球,而皮卡丘也一定会受到相应的伤害;如果选择离开它,那么小智不会损失精灵球,皮卡丘也不会损失体力。
小智的目标有两个:主要目标是收服尽可能多的野生小精灵;如果可以收服的小精灵数量一样,小智希望皮卡丘受到的伤害越小(剩余体力越大),因为他们还要继续冒险。
现在已知小智的精灵球数量和皮卡丘的初始体力,已知每一个小精灵需要的用于收服的精灵球数目和它在被收服过程中会对皮卡丘造成的伤害数目。请问,小智该如何选择收服哪些小精灵以达到他的目标呢?
- 输入
- 输入数据的第一行包含三个整数:N(0 < N < 1000),M(0 < M < 500),K(0 < K < 100),分别代表小智的精灵球数量、皮卡丘初始的体力值、野生小精灵的数量。
之后的K行,每一行代表一个野生小精灵,包括两个整数:收服该小精灵需要的精灵球的数量,以及收服过程中对皮卡丘造成的伤害。 - 输出
- 输出为一行,包含两个整数:C,R,分别表示最多收服C个小精灵,以及收服C个小精灵时皮卡丘的剩余体力值最多为R。
- 样例输入
-
样例输入1:
10 100 5
7 10
2 40
2 50
1 20
4 20 样例输入2:
10 100 5
8 110
12 10
20 10
5 200
1 110 - 样例输出
-
样例输出1:
3 30 样例输出2:
0 100 - 提示
- 对于样例输入1:小智选择:(7,10) (2,40) (1,20) 这样小智一共收服了3个小精灵,皮卡丘受到了70点伤害,剩余100-70=30点体力。所以输出3 30
- 对于样例输入2:小智一个小精灵都没法收服,皮卡丘也不会收到任何伤害,所以输出0 100
- 代码:
/*一个普通的二维01背包,注意体力不能是0,就可以了,
f[j][k]表示在使用了j个球,收到k点伤害的最大捕捉数目。
ans最好DP中更新,因为DP结束以后,最优值可能存在很多位置,伤害和球的数目不一定恰好用完
*/
#include<iostream>
using namespace std;
#include<cstdio>
#define N 1001
#define M 501
int n,m,k;
struct Jl{
int qiu,dam;
};
Jl jl[];
struct Ans{
int sum,tl;
};
Ans ans;
int f[N][M];
void input()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=;i<=k;++i)
{
scanf("%d%d",&jl[i].qiu,&jl[i].dam);
}
}
void DP()
{
ans.sum=;
ans.tl=m;
for(int i=;i<=k;++i)
for(int j=n;j>=jl[i].qiu;--j)
for(int k=m-;k>=jl[i].dam;--k)
{
f[j][k]=max(f[j][k],f[j-jl[i].qiu][k-jl[i].dam]+);
if((f[j][k]>ans.sum)||(f[j][k]==ans.sum&&(m-k)>ans.tl))
{
ans.sum=f[j][k];
ans.tl=m-k;
}
}
}
int main()
{
input();
DP();
printf("%d %d\n",ans.sum,ans.tl);
return ;
}
2016.4.9 NOI codevs动态规划专练的更多相关文章
- 2016. 4.10 NOI codevs 动态规划练习
1.codevs1040 统计单词个数 1040 统计单词个数 2001年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 De ...
- 10-19 dp专练
dp专练,终于克服了一次自己对dp的恐惧,磕出来一道题. 得分情况: T1:0 T2:0 T3:0 emmmm,磕出来的题是T2,但是因为初始化和int long long的原因爆零了 T1:n只狼排 ...
- P1251 递推专练3
递推专练3 描述 Description 圆周上有N个点.连接任意多条(可能是0条)不相交的弦(共用端点也算相交)共有多少种方案? 输入格式 Input Format 读入一个数N.<=N< ...
- 2016.4.3 动态规划NOI专练 王老师讲课整理
1.6049:买书 总时间限制: 1000ms 内存限制: 65536kB 描述 小明手里有n元钱全部用来买书,书的价格为10元,20元,50元,100元. 问小明有多少种买书方案?(每种书可购买 ...
- dp专练
dp练习. codevs 1048 石子归并 区间dp #include<cstdio> #include<algorithm> #include<cstring> ...
- 2016.11.17 NOI plus day0
今天很乱乱乱乱 根本不想写代码 玩了一早上了 昨晚失眠了 今天又懵逼了 中午就要走了 明天就要考试了 考完试回来就要补文化课了 现在我的内心很平静 因为已经紧张的冻结了 你知道什么叫彷徨么? 机房里的 ...
- 8.1搜索专练DFS和BFS
这是第一次全部做出来的依次练习了,有一些都是做过两遍了的,但是还是错了几回,更多时候我还是应该多注意下细节,就好像章爷笑我 的一样,像什么vis[]标记没清0,什么格式错误,还有什么题目没看清,还是的 ...
- Contest 7.21(贪心专练)
这一次都主要是贪心练习 练习地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26733#overview Problem APOJ 13 ...
- contest7.20(暴力专练)
此次练习的地址: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26732#overview 密码 acmore Problem A(P ...
随机推荐
- c语言中的size_t
size_t unsigned int 类型,无符号,它的取值没有负数.用来表示 参数/数组元素个数,sizeof 返回值,或 str相关函数返回的 size 或 长度.sizeof 操作符的结果类型 ...
- Linux汇编教程04:寻址方式
这一节,我们主要来讨论寻址方式,这一点十分重要. 我们上一节有稍微提了一下,内存地址引用的通用格式: 地址或偏移(%基址寄存器, %索引寄存器, 比例因子 ) 结果地址 = 地址或偏移 + %基址寄存 ...
- caffe Python API 之激活函数ReLU
import sys import os sys.path.append("/projects/caffe-ssd/python") import caffe net = caff ...
- MACBOOK 总是断网怎么办
MACBOOK 连接 wifi 老是断网.焦躁不安 看图,二个方法,第一就搞定,
- vue数据绑定方式:
1,{{ }} 2,v-text 3,v-html 前两种接受普通变量,第三种绑定带有标签的内容,但是严禁使用,这个会有 XSS危险,(将字符串解析成源代码) 4,v-bind:title=‘m ...
- 几条学习python的建议
熟悉python语言, 以及学会python的编码方式. 熟悉python库, 遇到开发任务的时候知道如何去找对应的模块. 知道如何查找和获取第三方的python库, 以应付开发任务. 学习步骤 安装 ...
- leetcode 之Rotate List(18)
这题我的第一想法是用头插法,但实际上并不好做,因为每次都需要遍历最后一个.更简单的做法是将其连成环,找到相应的位置重新设头结点和尾结点.这过 有很多细节需要注意,比如K有可能是大于链表长度的,如何重新 ...
- elasticsearch批量删除(查询删除)
注:delete by query只适用于低于elasticsearch2.0的版本(不包含2.0).有两种形式: 1.无请求体 curl -XDELETE 'localhost:9200/twitt ...
- 深入理解python多进程编程
1.python多进程编程背景 python中的多进程最大的好处就是充分利用多核cpu的资源,不像python中的多线程,受制于GIL的限制,从而只能进行cpu分配,在python的多进程中,适合于所 ...
- 【转载】Python: Enum枚举的实现
转自:http://www.cnblogs.com/codingmylife/archive/2013/05/31/3110656.html 从C系语言过来用Python,好不容易适应了写代码不打 ...