回顾一些较简单的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 行一个 ...
随机推荐
- 通过Get-Group导出组的成员
导出组邮箱的前十个成员,需要注意的是: Get-Group没有Get-GroupMember命令,但是在结果中有一个Members的属性,这个属性包含了所有子成员的对象,用循环将它们列出来即可.有点对 ...
- 【.Net】c# 让double保留两位小数
1.Math.Round(0.333333,2);//按照四舍五入的国际标准2. double dbdata=0.335333; string str1=String.Format(&qu ...
- JVM类加载机制详解(二)类加载器与双亲委派模型
在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...
- 反Nim博弈
原文地址:https://blog.csdn.net/xuejye/article/details/78975900 在尼姆博奕中取完最后一颗糖的人为赢家,而取到最后一颗糖为输家的就是反尼姆博奕.这道 ...
- USACO Section 1.5 Prime Palindromes 解题报告
题目 题目描述 题目就是给定一个区间[a,b]((5 <= a < b <= 100,000,000)),我们需要找到这个区间内所有既是回文串又是素数的数字. 输入样例 5 500 ...
- Mac上安装python3并设置SublimeREPL插件默认运行python3
1.安装python3 $ brew search python $ brew install python3 这里安装完后不需要单独添加环境变量,程序已经处理好,可以直接运行python3命令. $ ...
- Android Studio快捷键设置之实现原eclipse中ctrl+m的全屏的效果
如下图,keymap设置成eclipse的的,但是鼠标双击最大化复原没有,ctr+M全屏也没有, 那么久在如下图的三个项目上添加鼠标双击和快捷键---自己方便好用,但不冲突的 Toggle full ...
- python的if条件语句的语法和案例
1.条件语句 缩进用4个空格 if条件: #条件成功, else: #条件不成功 if条件:{ #条件成功, #条件成功, }else{ #条件不成功, #条件不成功, } if的语法就是这样或者是用 ...
- python【数据类型:列表与元组】
python列表: 定义一个列表:cities=['北京','上海','广州','深圳'] 注意:列表的下标0表示第一个元素,下标-1表示最后一个元素 列表增加元素 在列表末尾添加一个元素:citie ...
- python中__init__()、__new__()、__call__()、__del__()用法
关于__new__()的用法参考: http://www.myhack58.com/Article/68/2014/48183.htm 正文: 一.__new__()的用法: __new__()是在新 ...