动态规划测试test20170525
来源:互联网 发布:php抽象类和接口的作用 编辑:程序博客网 时间:2024/05/19 11:48
前言
由于自己的一些年级组那边的事情影响了当时考试时的心情,然后就A了第一题就没什么心思去搞其他题目了,这是很不好的。
题目
火 车 票(ticket.cpp)
Timelimit :0.1s Name :Ticket
一个铁路线上有 n(2<=n<=10000)个火车站,每个火车站到该线路的首发火车站距离都是已知的。任意两站之间的票价如下表所示:
站之间的距离 – X 票价 0≤X≤L1 C1 L1≤X≤L2 C2 L2≤X≤L3 C3 其中
L1,L2,L3,C1,C2,C3 都是已知的正整数,且(1≤L1<L2<L3≤109 ,1≤C1≤C2≤C3≤109 )。显然若两站之间的距离大于L3 ,那么从一站到另一站至少要买两张
票。注意:每一张票在使用时只能从一站开始到另一站结束。
任务
对于给定的线路,求出从该线路上的站 A 到站 B 的最少票价。
输入
输入文件的第一行为 6 个整数,L1,L2,L3,C1,C2,C3(1≤L1≤L2≤L3≤109,1≤C1≤C2≤C3≤109) ,这些整数由空格隔开.第二行为火车站的数量 N (2≤N≤10000 ).
第三行为两个不同的整数 A、B,由空格隔开。接下来的 N-1 行包含从第一站到其他站之间
的距离.这些距离按照增长的顺序被设置为不同的正整数。相邻两站之间的距离不超过L3 .
两个给定火车站之间行程花费的最小值不超过109 ,而且任意两站之间距离不超过109 。
输出
输出文件中只有一个数字,表示从 A 到 B 要花费的最小值.
样例输入
3 6 8 20 30 40
7
2 6
3
7
8
13
15
23
样例输出
70
题解:
这题目原来一本通的习题上有,不过不要优化
代码:
#include <cstdio>#include <cstring>#include <algorithm>#define Max(a,b) ((a)>(b)?(a):(b))#define Min(a,b) ((a)<(b)?(a):(b))typedef long long LL;const int maxn = 10000+10;const int INF = 2e9;inline int read(int &in) { in=0;int f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1; for(;ch>='0'&&ch<='9';ch=getchar()) in=in*10+ch-'0'; return in*f;}int n,sta,lst;int l[5],c[5];int k[5],p[5];int f[maxn];int dist[maxn],dis;namespace my_self { void init() { for(int i=1;i<maxn;i++) f[i]=0; read(l[1]);read(l[2]);read(l[3]);read(c[1]);read(c[2]);read(c[3]); read(n);read(sta);read(lst); dist[1]=0; for(int i=2;i<=n;i++) read(dist[i]); } void work() { p[1]=l[1];p[2]=l[2];p[3]=l[3];k[1]=k[2]=k[3]=sta; for(int i=sta+1;i<=lst;i++) { dis=dist[i]-dist[i-1];f[i]=INF; for(int j=1;j<=3;j++) { if(dis<=p[j]) { p[j]-=dis; if(f[k[j]]+c[j]<f[i]) f[i]=f[k[j]]+c[j]; } else { while(k[j]<i) { k[j]++;if(dist[i]-dist[k[j]]<=l[j]) break; } if((k[j]<=i) && (dist[i]-dist[k[j]]<=l[j])) { p[j]=l[j]-(dist[i]-dist[k[j]]); f[i]=Min(f[i],c[j]+f[k[j]]); } else p[j]=l[j]; } } } printf("%d\n",f[lst]); }}int main() { freopen("ticket.in","r",stdin); freopen("ticket.out","w",stdout); my_self::init(); my_self::work(); return 0;}
艺术馆的火灾(fire.cpp)
背景描述
这幢古老的建筑是一个艺术馆,它珍藏着上百件绘画、雕塑以及其他艺术品,就连建筑本身也是一件艺术。但是,岁月并不在乎它的精致与美丽,时光在渐渐剥夺着这幢木屋的生命。终于,在一个月色昏暗的夜晚,它着火了。艺术馆是一幢两层的小楼,每一层有 N 个房间,每个房间中收藏的艺术品的价值都可以用一个正整数来表示。下面是一个 N=4 的例子。
屋顶
40 50 30 60
30 30 40 20
在这个例子中,二层楼的第四个房间中艺术品的价值最大,为 60。而一层楼的第四个房间中艺术品的价值仅为 20。在消防队员火速赶到的时候,火势已经蔓延了整个建筑,消防队员们观察每个房间中的火势,将它们分别用一个正整数来表示。在上面的例子中,各房间中的火势可能如下。
屋顶
50 40 50 70
40 50 20 30
你可以看到,二层楼的第四个房间中火势最强,为 70。而一层楼的第三个房间中火势较弱,为 20。
由于火情紧急,消防队员们准备使用一种新型的灭火器。这种灭火器只能发射 K 次,每次发射将覆盖一个矩形的区域(矩形的高度可以是 1 也可以是 2)。它的威力巨大,所到之处不但火焰会被扑灭,就连同在一处的艺术品也难以幸免。因此,如何善用这种灭火器成了最大的问题。一个例子:如果灭火器的一次发射覆盖了下图阴影所示的 2×2 矩形区域,那么这四个房间的火势和艺术品价值都将成为 0。
任务说明
给出艺术馆每层的房间数 N 和灭火器的发射次数 K,以及每个房间中艺术品的价值和火势,你需要决定灭火器每次应该怎样发射(也可以不发射),才能将这次火灾的损失降到最低限度。这个损失用你所摧毁的艺术品的总价值,加上剩余的火势总值(这些火焰将需要消防队员们亲身去扑灭)来衡量。
输入数据
输入文件的第一行有两个整数 N(1 <= N <= 100)、K(1<= K <= 10),分别表示艺术馆中每层的房间数和灭火器的发射次数。
接下来的两行每行有 N 个整数,其中第 4-i 行的第 j 个整数 Vi,j表示的是第 i层第 j 个房间中艺术品的价值(1 <= i <= 2,1 <= j <= N,1 <= Vi,j <= 10000)。
再接下来的两行每行也有 N 个整数,其中第 6-i 行的第 j 个整数 Fi,j 表示的是第 i 层第 j 个房间中的火势(1 <= i <=2,1 <= j <= N,1 <= Fi,j <= 10000)。
输出数据
你的输出文件应该有 K 行,每行有四个整数 L1、R1、L2、R2,表示你的灭火器的一次行动。如果灭火器这次不发射,那么这四个整数都为 0;否则这次发射所覆盖的矩形区域的左下角是第 L1 层的第 R1 个房间,右上角是第 L2 层的第R2 个房间。
注意:你的每次发射所覆盖的矩形区域必须位于小楼之内,并且矩形的面积至少为 0。即 1 <= L1 ,L2 <= 2,1 <= R1 , R2 <= N。
输入输出样例
fire.in
4 2
40 50 30 60
30 30 40 20
50 40 50 70
40 50 20 30
fire.out
1 1 1 2
2 3 2 4
样例解释
摧毁艺术品:30+60+30+30=150
剩余火势:50+40+20+30=140
最小损失:150+140=290
评分标准
每个测试点都有一定的时间限制。你的程序只有在规定的时限内输出解,并且按照你的方案来发射灭火器可以将损失降到最小,你才会得到相应测试点的分值;否则这个测试点不得分。
注意:本题的解不一定是唯一的。即对于一个测试数据,可能有多种发射灭火器的方案
都可以使损失达到最小。在这种情况下,你只要输出最优方案中的任意一种即可。
题解:
首先将问题转化成模型:在一个2×N的矩阵中,找出K个子矩阵。我们将这些子矩阵所包含的元素集合用S来表示的话,那么问题的目标就是使
因为
下面是规划方程:
边界条件
然后输出就得在状态转移时记录即可。
代码:
#include <iostream> #include <fstream> #include <cassert> using namespace std; ifstream fin("Input.txt"); ofstream fout("Output.txt"); int room_n,shoot_k,v[3][101],f[3][101]; /*dp部分*/ int dp[101][5][11];//[i][j][k]:前i列已经最少有k个完整矩形、第i列的状态为j之后还能获得的最小损失 bool checked[101][5][11]; int memo(int i,int j, int k); int loss(int i, int j); //memo调用的子过程,返回第i行决策为j时的净损失 /*最优解的构造部分*/ int build[101][5][11]; //记录(i,j,k)状态下要得到最优解,i+1列的状态 bool room[3][101]; void paint(int i, int j, int k);//在room中标出状态(i,j,k)后的灭火器使用情况 /*最优解的输出部分*/ int counter;//记录发射次数 void output(int i); //输出矩形 int main() { /*输入部分*/ fin >> room_n >> shoot_k; for(int i=2;i>=1;i--) for(int j=1;j<=room_n;j++) fin >> v[i][j]; for(int i=2;i>=1;i--) for(int j=1;j<=room_n;j++) fin >> f[i][j]; /*计算部分*/ unsigned min_loss=memo(0,0,0); paint(0,0,0); /*输出部分*/ for(int i=1;i<=room_n;i++) output(i); for(int j=shoot_k-counter;j>=1;j--) fout << "0 0 0 0\n"; return 0; } // int memo(int i,int j, int k) { if(checked[i][j][k]) return dp[i][j][k]; if(i==room_n) return 0; dp[i][j][k]=INT_MAX; for(int jj=0,kk,ans;jj<=3;jj++) //枚举第i+1行状态 { if(jj==3&&(j==4||j==1||j==2)) jj++; //上下都用时的状态修正 kk=k+!(jj==0||jj==j||j==4); if(kk<=shoot_k) ans=memo(i+1,jj,kk)+loss(i+1,jj); else ans=INT_MAX; if(dp[i][j][k]>ans) { dp[i][j][k]=ans; build[i][j][k]=jj; } } assert(dp[i][j][k]<INT_MAX); checked[i][j][k]=true; return dp[i][j][k]; } int loss(int i, int j) { /*状态j的定义: 0:上层下层都不使用灭火器; 1:上使用;2:下使用;3,4:上下都用 其中3表示与此列相连的使用灭火器的房间最少组成1个完整矩形 4表示与此列相连的使用灭火器的房间已经最少组成2个完整矩形*/ switch(j) { case 0: return (f[1][i]+f[2][i]); //上下都不用 case 1: return(v[2][i]+f[1][i]); //上用 case 2: return(v[1][i]+f[2][i]); //下用 case 3: //上下都用 case 4: return(v[1][i]+v[2][i]); } assert(0); } // void paint(int i, int j, int k) { if(i==room_n) return; assert(checked[i][j][k]); int jj=build[i][j][k]; int kk=k+!(jj==0||jj==j||j==4); switch(jj) { case 0: break; //上下都不用 case 1: room[2][i+1]=1; break; //上用 case 2: room[1][i+1]=1; break; //下用 case 3: case 4: room[1][i+1]=room[2][i+1]=true; break; //上下都用 default: assert(0); } paint(i+1,jj,kk); } // void output(int i) { counter++; int ii; if(room[2][i]&&!room[1][i]) //上用 { fout << 2 << ' ' << i << ' '; for(ii=i;ii<=room_n&&room[2][ii];ii++) room[2][ii]=0; fout << 2 << ' ' << ii-1 << endl; } else if(room[1][i]&&!room[2][i]) //下用 { fout << 1 << ' ' << i << ' '; for(ii=i;ii<=room_n&&room[1][ii];ii++) room[1][ii]=0; fout << 1 << ' ' << ii-1 << endl; } else if(room[1][i]&&room[2][i]) //上下都用 { fout << 1 << ' ' << i << ' '; for(ii=i;ii<=room_n&&room[1][ii]&&room[2][ii];ii++) room[1][ii]=room[2][ii]=0; fout << 2 << ' ' << ii-1 << endl; } else counter--; //上下都不用 } //
序列压缩(substract.cpp)
给出一个 N 个正整数的序列 A=[A1,A2,……,AN],我们可以对其进行压缩操作.所谓压缩
操作是指:将两个相邻的元素 AI和 AI+1的差(AI-AI+1)去替代第 I 个元素,同时删去第 I+1 个元素,严格地可以定义如下:
CON(A,I)=[A1,,A2,….,AI-1,AI-AI+1,AI+2,…….AN]
经过一次序列压缩之后,我们可以得到一个 N-1 个元素的序列,如此进行下去,我们可以仅得到单一的一个整数。如下例所示:
con([12 ,10, 4, 3, 5],2)=[12 ,6,3,5]
con([12,6,3,5],3)=[12 ,6,-2]
con([12,6,-2],2)=[12,8]
con([12,8],1)=[4]
现给定一个正整数序列和一个目标整数 T,求解并输出压缩顺序。
输入文件:
N T (1〈=N〈=100,-10000〈=T〈=10000)
A1 A2 AN
输出文件:
压缩顺序;
输入输出示例:
SUBSTRACT.IN
5 4
12 10 4 3 5
SUBSTRACT.OUT
2 3 2 1
题解:
我们可以把题目转化为在一列数中添加+ - 。
我们记所有加上 -号的数的和为S,所有数的和为sum,容易得到S=(sum-T)/2;
用
代码:
#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <iostream>using namespace std;#define Max(a,b) ((a)>(b)?(a):(b))#define Min(a,b) ((a)<(b)?(a):(b))typedef long long LL;const int maxn = 10010;int num[maxn],pre[maxn],vis[maxn];int sum,n,t,m;bool ps[maxn];string st;char str[maxn];char del (char *s,int p) { char ch; if(p>=strlen(s) or p<0) return 0; ch=s[p]; for(int i=p;s[i];i++) s[i]=s[i+1]; return ch;}namespace my_self { void init() { scanf("%d%d",&n,&t); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); sum+=num[i]; } m=(sum-t)/2; } void work() { vis[num[2]]=true;pre[num[2]]=2; for(int i=3;i<=n;i++) { if(vis[m]) break; for(int j=m;j>=num[i];j--) { if(!vis[j]) { if(vis[j-num[i]]) { vis[j]=true;pre[j]=i; } } } } } void print() { for(int i=1;i<maxn;i++) ps[i]=true; int s=m; while(s>0) { ps[pre[s]]=false;s-=num[pre[s]]; } for(int i=2;i<=n;i++) { if(ps[i]) st=st+'+'; else st=st+'-'; } for(int i=0;i<st.length();i++) str[i]=st[i]; char *pch=strchr(str,'+'); while(pch!=NULL) { printf("%d ",pch-str+1); del(str,pch-str); pch=strchr(str,'+'); } for(int i=0;i<strlen(str);i++) putchar('1'),putchar(' '); putchar(10); }}int main() { freopen("substract.in","r",stdin); freopen("substract.out","w",stdout); my_self::init(); my_self::work(); my_self::print(); //std::cout<<st<<std::endl; return 0;}/*5 412 10 4 3 5*/
- 动态规划测试test20170525
- 动态规划测试test20170430
- 动态规划测试test20170506
- 动态规划测试test20170511
- 动态规划测试test20170520
- 动态规划测试test20170513
- 动态规划测试test20170518
- 动态规划测试3(test20170406)
- 【DP】TEST20170525
- 动态规划!!!动态规划!!!
- 卷积和动态规划的简单测试程序
- 5月6日动态规划测试解题报告
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- Camera电源噪声处理
- 在32位ubuntu中安装docker并启动容器
- spring中bean的生命周期
- 编程入门必知——Windows命令提示符启动与使用
- 无水印火山小视频下载教程
- 动态规划测试test20170525
- 加密 【打表】
- unsigned char和signed char型变量的区别,赋值后它在内存中的存储形式
- awk命令介绍
- 无法打开谷歌网上应用商店来下载安装扩展程序?
- Python——socket编程
- Netty私有栈协议
- ZipException
- js中常用的遍历函数