回顾一些较简单的dp题
两问:一个导弹拦截系统最多能拦多少导弹 要拦截所有导弹至少需要多少拦截系统
第一问感觉是一个比较巧妙的方法:
维护一个单调递减的序列 length[] 记录的是拦截导弹的高度
当下一个导弹小于 length[] 最后一个数(最小的数)则直接把它加在序列后即可
若大于 则找到序列中比它大的最小的数(二分)然后替换 可以保证最优
第二问 就是贪心啊
当现有的导弹系统的拦截高度都小于当前导弹的高度 则开一个新的系统
否则找到拦截高度比导弹高度高的最小的系统来拦截
这里记录系统拦截高度的数组一定是单调递增的无需排序
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int x;
bool f;
int height[],length[],minh[];
int main()
{
int y=;
while(scanf("%d",&height[y])==) y++;y--;
length[]=height[];
int top=;
for(int i=;i<=y;i++)
{
if(height[i]<=length[top]) length[++top]=height[i];
else
{
int left=,right=top,ans;
while(left<=right)
{
int mid=(left+right)/;
if(length[mid]<height[i])
{
ans=mid;
right=mid-;
}
else left=mid+;
}
length[ans]=height[i];
}
}
cout<<top<<endl;
int maxa=;
for(int i=;i<=y;i++)
if(maxa<length[i]) maxa=length[i];
int num=;minh[]=height[];
for(int i=;i<=y;i++)
{
f=;
for(int j=;j<=num;j++)
if(height[i]<=minh[j]) {minh[j]=height[i];f=;break;}
if(f==) minh[++num]=height[i];
}
cout<<num;
return ;
}
区间dp一般套路:枚举起点 枚举区间长度(或终点) 枚举断点 转移
注意枚举的顺序要保证由已知推未知
很多时候遇到环都可能要断环为链(图论也是这样)
#include<iostream>
using namespace std;
int a[];
int s[];
int ans1[][];
int ans2[][];
int main()
{
int n;
cin>>n;
for(int i=;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-]+a[i];
a[i+n]=a[i];
}
for(int i=n+;i<=n*;i++)
s[i]=s[i-]+a[i];
for(int i=;i<=*n;i++)
for(int j=;j<=*n;j++)
if(j!=i) ans2[i][j]=;
for(int h=;h<=n;h++)
{
for(int i=h+n-;i>=h;i--)
{
for(int j=i;j<=h+n-;j++)
{
for(int k=i+;k<=j;k++)
{
ans1[i][j]=max(ans1[i][j],ans1[i][k-]+ans1[k][j]+s[j]-s[i-]);
ans2[i][j]=min(ans2[i][j],ans2[i][k-]+ans2[k][j]+s[j]-s[i-]);
}
}
}
}
int maxn,minn=;
for(int i=;i<=n;i++)
{
maxn=max(maxn,ans1[i][i+n-]);
minn=min(minn,ans2[i][i+n-]);
}
cout<<minn<<endl<<maxn<<endl;
return ;
}
现在看起来好像很显然的样子
f[i][j] 表示第一个字符串匹配到第i位 第二个字符串匹配到第j位最大的相似度
三种情况转移 分别是在第一个,第二个字符串加空碱基 不加空碱基
注意初始化
#include<iostream>
#include<cstdio>
using namespace std;
int len1,len2,sum;
char s1[],s2[];
int a1[],a2[];
char ch;
int f[][];
int s[][]={{,,,,,},
{,,-,-,-,-},
{,-,,-,-,-},
{,-,-,,-,-},
{,-,-,-,,-},
{,-,-,-,-,}};
int change(char x)
{
if(x=='A') return ;
else if(x=='C') return ;
else if(x=='G') return ;
else if(x=='T') return ;
}
int main()
{
scanf("%d",&len1);ch=getchar();
for(int i=;i<=len1;i++) scanf("%c",&s1[i]);
scanf("%d",&len2);ch=getchar();
for(int i=;i<=len2;i++) scanf("%c",&s2[i]);
for(int i=;i<=len1;i++) a1[i]=change(s1[i]);
for(int i=;i<=len2;i++) a2[i]=change(s2[i]);
for(int i=;i<=len1;i++)
for(int j=;j<=len2;j++) f[i][j]=-;
for(int i=;i<=len1;i++) f[i][]=f[i-][]+s[a1[i]][];
for(int i=;i<=len2;i++) f[][i]=f[][i-]+s[a2[i]][];
for(int i=;i<=len1;i++)
{
for(int j=;j<=len2;j++)
{
f[i][j]=max(f[i][j],f[i-][j]+s[a1[i]][]);
f[i][j]=max(f[i][j],f[i][j-]+s[a2[j]][]);
f[i][j]=max(f[i][j],f[i-][j-]+s[a1[i]][a2[j]]);
}
}
printf("%d",f[len1][len2]);
return ;
}
四维dp 优化成三维
#include<iostream>
#include<cstdio>
using namespace std;
int read()
{
int ans=;char c;
c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<='') {ans=ans*+c-'';c=getchar();}
return ans;
}
int f[][][];
int a[][];
int main()
{
int m=read(),n=read();
for(int i=;i<=m;i++)
for(int j=;j<=n;j++)
a[i][j]=read();
for(int k=;k<=n+m;k++)
{
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
if(k-i+<||k-j+<) continue;
f[k][i][j]=max(max(max(f[k-][i][j],f[k-][i-][j]),f[k-][i][j-]),f[k-][i-][j-]);
f[k][i][j]+=a[k-i][i]+a[k-j][j];
if(i==j) f[k][i][j]-=a[k-i][i];
}
}
}
cout<<f[m+n][n][n];
return ;
}
这一题要输出最优方案 所以f[i][j]表示的是前i束花放在前j个瓶子里 且第i束花放在第j个瓶子里的最大美学值
#include<iostream>
using namespace std;
int a[][]; //a[i][j] 第i束花放在第j个花瓶中的美学值
int b[][]; //b[i][j] 前i束花放在前j个花瓶中的最大美学值
int c[][],d[];
int main()
{
int f,v;
cin>>f>>v;
for(int i=;i<=f;i++)
for(int j=;j<=v;j++)
cin>>a[i][j];
//for(int i=1;i<=v-f+1;i++) b[1][i]=a[1][i];
for(int i=;i<=f;i++)
for(int j=;j<=v;j++)
b[i][j]=-;
/*如果b数组中初始值都为0
那么当第一束花放在前几个花瓶中美学值为负数时就会出错;
或:直接初始化第一束花放在前几个花瓶中的美学值(前面被注释掉的)
但注意此时后面一个循环的i从2开始*/ for(int i=;i<=f;i++)
for(int j=i;j<=v-f+i;j++) //j<=v-f+i!!!
for(int k=i-;k<=j-;k++)
{
if(b[i][j]<b[i-][k]+a[i][j])
{
b[i][j]=b[i-][k]+a[i][j];
c[i][j]=k;
}
}
int maxn=-,k;
for(int i=f;i<=v;i++)
{
if(b[f][i]>maxn)
{
maxn=b[f][i];
k=i;
}
}
cout<<maxn<<endl;
for(int i=;i<=f;i++)
{
d[i]=k;
k=c[f-i+][k];
}
for(int j=f;j>=;j--) cout<<d[j]<<" ";
return ;
}
和3类似
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char a[],b[];
int f[][];
int main()
{
int m,n,i,j;
scanf("%s%s",a,b);
m=strlen(a);n=strlen(b);
for(int i=m+;i>=;i--) a[i]=a[i-];
for(int j=n+;j>=;j--) b[j]=b[j-];
for(i=;i<=m;i++) f[i][]=i;
for(j=;j<=n;j++) f[][j]=j;
for(i=;i<=m;i++)
{
for(j=;j<=n;j++)
{
if(a[i]==b[j]) f[i][j]=f[i-][j-];
else
{
f[i][j]=min(min(f[i-][j-],f[i-][j]),f[i][j-])+;
}
}
}
cout<<f[m][n];
return ;
}
f[i][j] 表示到第i位数已经加了j个乘号的最大乘积
加高精有点麻烦啊
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define rg register
#define M 110
using namespace std;
int read()
{
int x=,y=;char c;
c=getchar();
while(c<''||c>'') {if(c=='-') y=-;c=getchar();}
while(c>=''&&c<='') {x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
string ss;
int n1,k1;
int a[M];
struct node
{
int s[M];
int len;
}f[][M];
node calc(node x,int l,int r)
{
node x1,y1;y1.len=r-l+;
int len1=x.len,len2=y1.len,len=len1+len2-;
memset(x1.s,,sizeof(x1.s));
memset(y1.s,,sizeof(y1.s));
for(rg int i=r;i>=l;i--) y1.s[r-i+]=a[i];
for(rg int i=;i<=len1;i++)
for(rg int j=;j<=len2;j++)
x1.s[i+j-]+=x.s[i]*y1.s[j];
for(rg int i=;i<=len;i++)
{
x1.s[i+]+=x1.s[i]/;
x1.s[i]%=;
}
if(x1.s[len+]) len++;
x1.len=len;
return x1;
}
node cmp(node x,node y)
{
int len1=x.len,len2=y.len;
if(len1<len2) return y;
if(len1>len2) return x;
for(rg int i=len1;i>=;i--)
{
if(x.s[i]>y.s[i]) return x;
if(x.s[i]<y.s[i]) return y;
}
return y;
}
int main()
{
n1=read();k1=read();
cin>>ss;
for(int i=;i<=n1;i++) a[i]=ss[i-]-'';
for(int i=;i<=n1;i++)
for(int j=i;j>=;j--)
f[][i].s[++f[][i].len]=a[j];
for(int i=;i<=n1;i++) //前i个数
{
int maxn=min(i-,k1);
for(int k=;k<=maxn;k++)//k个乘号
for(int j=k;j<i;j++)//第k个乘号放哪
f[k][i]=cmp(f[k][i],calc(f[k-][j],j+,i));
}
for(int i=f[k1][n1].len;i>=;i--)
printf("%d",f[k1][n1].s[i]);
return ;
}
回顾一些较简单的dp题的更多相关文章
- 从一道简单的dp题中学到的...
今天想学点动态规划的知识,于是就看了杭电的课件,数塔问题啊,LCS啊都是比较经典的动规了,然后随便看了看就开始做课后练习题... HDOJ 1421 搬寝室 http://acm.hdu.edu.cn ...
- 一道简单的dp题 --- Greenhouse Effect CodeForces - 269B
题目链接: https://vjudge.net/problem/36696/origin 题目大意: 要求从1到m升序排列,点可以随意移动,问最少需要移动多少次, 思路: 动态规划 可以推出转移方程 ...
- [DP题]吃糖果
1944:吃糖果 总时间限制:1000ms内存限制:65536kB 描述 名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名(盒内共有 N 块巧克力,20 > N >0).妈妈告诉 ...
- [DP题]采药
1775:采药 总时间限制:1000ms内存限制:65536kB 描述 辰辰是个很有潜能.天资聪颖的孩子,他的梦想是称为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给 ...
- [DP题]最长上升子序列
最长上升子序列 总时间限制:2000ms 内存限制:65536kB 描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的.对于给定的一个序列( ...
- poj 2342 Anniversary party 简单树形dp
Anniversary party Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3862 Accepted: 2171 ...
- HDU 3853LOOPS(简单概率DP)
HDU 3853 LOOPS 题目大意是说人现在在1,1,需要走到N,N,每次有p1的可能在元位置不变,p2的可能走到右边一格,有p3的可能走到下面一格,问从起点走到终点的期望值 这是弱菜做的第 ...
- 古韵之乞巧 题解 dp题
[noip模拟赛1]古韵之乞巧 描述 闺女求天女,更阑意未阑. 玉庭开粉席,罗袖捧金盘. 向月穿针易,临风整线难. 不知谁得巧,明旦试相看. ——祖咏<七夕> 女子乞巧,是七夕的重头戏 ...
- [10.27_P2] 统计损失 (简单树形DP)
树形DP 简单题 Description 给定一棵树,每个节点有一个值.对于一条路径,它的值为路径上所有点的值的乘积.求出树上所有路径的值的和. 注意:单个点也算一条路径. Input 第 1 行一个 ...
随机推荐
- Windows下获取文件的md5码的方法
1.certutil 命令简介 本来想找一个工具 算一个文件的md5 或者是sha 值来着. 找到一个说法是 可以使用 windows 自带的命令行来处理 具体命令 certutil -hashfil ...
- JS 随机整数
<script> function GetRandomNum(Min,Max){ var Range = Max - Min; var Rand = Math.random() ...
- Hibernate 注解之 @Temporal
因为数据库中有个 Date类型的数据,在从数据库中获取数据[就是getXxx方法,当然,自动装配的时候可以直接写在字段上,但也只是针对getXxx方法,不会自动赋值]的时候可以利用这个 @Tempor ...
- Mininet 系列实验(一)
关于SDN的第一个实验,似乎实验室里的前辈们也都是从这里开始的. 实验内容 使用源码安装Mininet 参考 Mininet使用源码安装 实验环境 虚拟机:Oracle VM VirtualBox U ...
- WebSphere概要文件管理工具
manageprofiles:概要管理命令工具 3.1 模板 位于 <was_home>/profileTemplates.每个模板都由一组提供概要初始设置的文件和概要创建后将采取的操作列 ...
- jumpserver 堡垒机搭建
1.摘要 Jumpserver 是一款由python编写开源的跳板机(堡垒机)系统,实现了跳板机应有的功能.基于ssh协议来管理,客户端无需安装agent. 特点: 完全开源,GPL授权 Python ...
- linux内核设计与实现一书阅读整理 之第三章
chapter 3 进程管理 3.1 进程 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 内核调度的对象是线程而并非进程. 在现代操作系统中,进程提供两种虚拟机制: 虚拟处理器 ...
- nodejs进程异常退出处理方法
1. 捕获uncaughtException process.on('uncaughtException', function (err) { //打印出错误 console.log(err); // ...
- php 百家姓
private $surname = array('赵','钱','孙','李','周','吴','郑','王','冯','陈','褚','卫','蒋','沈','韩','杨','朱','秦','尤' ...
- Linux查看动态库.so导出函数列表
https://blog.csdn.net/chrisnotfound/article/details/80662923