The Triangle  http://poj.org/problem?id=1163

暴力dfs的话,每个节点有两条路可以走,那么n个节点复杂度就是2^n  n=100  超时   dp来做 就优化成 n^2

记忆化搜索,就能优化成n^2 因为一个点最多算一次,以后会直接返回dp i j 。 dp i j 表示这个位置能获得最大值。最后一行就是a i j  ,其他行都可以由下面两条路取最大值。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=;
int n,a[M][M],dp[M][M];
int dfs(int i,int j){
if(~dp[i][j]) return dp[i][j];
if(i==n) dp[i][j]=a[i][j];
else dp[i][j]=max(dfs(i+,j),dfs(i+,j+))+a[i][j];
return dp[i][j];
}
int main(){
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
for(int j=;j<=i;j++){
scanf("%d",&a[i][j]);
}
}
mt(dp,-);
printf("%d\n",dfs(,));
}
return ;
}

自底向上的推法,那dp i j 就表示i j 这个位置能获得的最大值, 然后dp i j 可以推向两个状态,分别是 dp i-1 j 和 dp i-1 j-1.  这是用当前状态去推能到达的所有状态的写法。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=;
int a[M][M],dp[M][M];
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
for(int j=;j<=i;j++){
scanf("%d",&a[i][j]);
}
}
mt(dp,);
for(int i=n+;i>=;i--){
for(int j=;j<=n;j++){
dp[i-][j]=max(dp[i-][j],dp[i][j]+a[i-][j]);
dp[i-][j-]=max(dp[i-][j-],dp[i][j]+a[i-][j-]);
}
}
printf("%d\n",dp[][]);
}
return ;
}

这是用所有能到达的状态推当前状态的写法,并且空间优化了一下,省去了输入的数组。

 #include<cstdio>
#include<algorithm>
using namespace std;
const int M=;
int dp[M][M];
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
for(int j=;j<=i;j++){
scanf("%d",&dp[i][j]);
}
}
for(int i=n-;i>=;i--){
for(int j=;j<=i;j++){
dp[i][j]=max(dp[i+][j],dp[i+][j+])+dp[i][j];
}
}
printf("%d\n",dp[][]);
}
return ;
}

最长上升子序列  http://bailian.openjudge.cn/practice/2757/

记忆化搜索

 #include<cstdio>
#include<algorithm>
using namespace std;
const int M=;
int n,a[M],dp[M];
int dfs(int i){
if(~dp[i]) return dp[i];
dp[i]=;
for(int j=i+;j<=n;j++){
if(a[i]<a[j]){
dp[i]=max(dp[i],dfs(j)+);
}
}
return dp[i];
}
int main(){
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
dp[i]=-;
}
int ans=;
for(int i=;i<=n;i++){
ans=max(ans,dfs(i));
}
printf("%d\n",ans);
}
return ;
}

用dp【i】表示以 i 为结尾的最长上升子序列的长度,可以得到它可以由前面所有值比他小的dp +1推过来。这是当前状态由其他所有能推过来的状态更新的写法。

 #include<cstdio>
#include<algorithm>
using namespace std;
const int M=;
int a[M],dp[M];
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
dp[i]=;
}
int ans=;
for(int i=;i<=n;i++){
for(int j=;j<=i;j++){
if(a[j]<a[i]){
dp[i]=max(dp[i],dp[j]+);
}
}
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
return ;
}

还是用dp【i】表示以 i 为结尾的最长上升子序列的长度,由当前状态去更新其他所有能更新的状态的写法。

 #include<cstdio>
#include<algorithm>
using namespace std;
const int M=;
int a[M],dp[M];
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
dp[i]=;
}
for(int i=;i<=n;i++){
for(int j=i+;j<=n;j++){
if(a[i]<a[j]){
dp[j]=max(dp[j],dp[i]+);
}
}
}
int ans=;
for(int i=;i<=n;i++){
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
return ;
}

Common Subsequence http://poj.org/problem?id=1458

用dp i j 表示a串以 i 结尾  b串 以 j 结尾的最长公共子序列长度,这个是当前状态通过其他所有状态推来的写法。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=;
char a[M],b[M];
int dp[M][M];
int main(){
while(~scanf("%s%s",a,b)){
mt(dp,);
int n=strlen(a);
int m=strlen(b);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(a[i-]==b[j-]){
dp[i][j]=max(dp[i][j],dp[i-][j-]+);
}
else{
dp[i][j]=max(dp[i-][j],dp[i][j-]);
}
}
}
printf("%d\n",dp[n][m]);
}
return ;
}

2755:神奇的口袋 http://bailian.openjudge.cn/practice/2755/

二进制枚举,暴力。

 #include<cstdio>
const int M=;
int a[M];
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<n;i++){
scanf("%d",&a[i]);
}
int all=<<n,ans=;
for(int i=;i<all;i++){
int sum=;
for(int j=;j<n;j++){
if((i>>j)&) sum+=a[j];
}
if(sum==) ans++;
}
printf("%d\n",ans);
}
return ;
}

dfs枚举,暴力

 #include<cstdio>
const int M=;
int a[M],ans,n;
bool use[M];
void dfs(int t){
if(t==n){
int sum=;
for(int i=;i<n;i++){
if(use[i]) sum+=a[i];
}
if(sum==) ans++;
return ;
}
use[t]=true;
dfs(t+);
use[t]=false;
dfs(t+);
}
int main(){
while(~scanf("%d",&n)){
for(int i=;i<n;i++){
scanf("%d",&a[i]);
}
ans=;
dfs();
printf("%d\n",ans);
}
return ;
}

dfs直接找解,递归,不用递归sum,k-1,用了递归sum-ak,k-1

 #include<cstdio>
int a[];
int dfs(int sum,int k){///return 前k个物品选和为sum的情况
if(sum==) return ;
if(k<=) return ;
return dfs(sum,k-)+dfs(sum-a[k],k-);
}
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
printf("%d\n",dfs(,n));
}
return ;
}

dp递推的找解,定义方式和上面一种一样,dp i j 表示前 i 个 和为 j 的情况,这个是由选和不选两种推出两个转移方程。

 #include<cstdio>
#include<cstring>
#define mt(a,b) memset(a,b,sizeof(a))
int a[];
int dp[][];
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
mt(dp,);
dp[][]=;
for(int i=;i<=n;i++){
for(int j=;j<=;j++){
dp[i][j]+=dp[i-][j];
if(j+a[i]<=)
dp[i][j+a[i]]+=dp[i-][j];
}
}
printf("%d\n",dp[n][]);
}
return ;
}

与上一dp相同,空间少了一维,我们只需知道某个和能达到的次数,所以输入一个个去更新所有的情况就行。这是由当前状态推向下一状态的写法。

 #include<cstdio>
#include<cstring>
#define mt(a,b) memset(a,b,sizeof(a))
int dp[];
int main(){
int n,a;
while(~scanf("%d",&n)){
mt(dp,);
for(int i=;i<=n;i++){
scanf("%d",&a);
for(int j=;j>=;j--){
if(dp[j]&&j+a<=){
dp[j+a]+=dp[j];
}
}
dp[a]++;
}
printf("%d\n",dp[]);
}
return ;
}

end

pku ppt some problem的更多相关文章

  1. PKU A Simple Problem with Integers (段树更新间隔总和)

    意甲冠军:一个典型的段树C,Q问题,有n的数量a[i] (1~n),C, a, b,c在[a,b]加c Q a b 求[a,b]的和. #include<cstdio> #include& ...

  2. 动态规划 is beginning。。。。。。。。。

    感觉动态规划非常模糊,怎么办呢??? 狂刷题吧!! !! ! !!! ! !!! !! ! ! ! .!! ..!.! PKU  PPt 动规解题的一般思路 1. 将原问题分解为子问题         ...

  3. 【解题报告】PKU 2826 An Easy Problem?!

    原题链接:http://poj.org/problem?id=2826 一题很蛋疼的一题.目前为止还有一个问题我没搞清楚,问题注在代码中. 题目大意: 外面下雨了,农民Johnoson的bull(?? ...

  4. PKU 3468 A Simple Problem with Integers

    题目大意: 有N,M两个数 Q 表示查询, 后面两个数a b,表示查询从a 到b计算它们的和 C 表示增加   后面三个数a,b,c 表示从a开始,一直到b,每个数都增加c 除了查询要进行输出,增加不 ...

  5. PKU 1208 The Blocks Problem(模拟+list应用)

    题目大意:原题链接 关键是正确理解题目意思 首先:介绍一下list容器的一些操作:参考链接 list<int> c1; c1.unique();              去重. c1.r ...

  6. PJOI PKU Campus 2011 B:A Problem about Tree LCA 求随意点x为根的y的父节点

    题目链接:点击打开链接 题意:给定n个点 m个询问 以下n-1行给定一棵树 m个询问 x y 问把树转成以x为根 y的父节点是谁 第一种情况lca==y那就是x的第 dep[x] - dep[y] - ...

  7. 刘汝佳黑书 pku等oj题目

    原文地址:刘汝佳黑书 pku等oj题目[转]作者:小博博Mr 一.动态规划参考资料:刘汝佳<算法艺术与信息学竞赛><算法导论> 推荐题目:http://acm.pku.edu. ...

  8. HDU——PKU题目分类

    HDU 模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 ...

  9. BZOJ 2301 Problem b

    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2301 冬令营听了莫比乌斯,这就是宋老师上课讲的例题咯[今天来实现一下] #include& ...

随机推荐

  1. 什么叫wipe,安卓用户如何去wipe?

    一.wipe是什么意思 wipe从英文单词的字面意思来理解就是:揩,擦;揩干,擦净的意思,从刷机爱好者的专业角度来理解可以认为是一种对手机数据擦除的操作.关于wipe是什么意思比较专业的解答为:wip ...

  2. 下拉框的选择跳转事件(jqure)

    <select id="coupontype"> <option value="@CouponType.全部" href="@Url ...

  3. GForms 快速入门指南

    本文旨在帮助您快速安装.创建及运行GForms应用. 1.   启动GForms Eclipse 如果您没有GForms安装介质,请到如下地址:http://yun. baidu .com/s/1bn ...

  4. Session State Pattern会话状态模式

    Client Session State 客户会话状态. 在Client端保存会话状态. 运行机制 Client在每次请求时会把所有的会话数据传给Server,Server在响应时把所有的会话状态传给 ...

  5. IPv6协议介绍

    IPv6是为了解决基于IPv4的TCP/IP协议簇遇到的问题而推出的下一代IP协议.由于IPv4中采用的编制方式使得可用的网络地址和主机地址的数目远低于理论数目,随着全球互联网的快速发展,现有的IPv ...

  6. android网络编程

    android的网络编程分为2种:基于socket的,和基于http协议的. 基于socket的用法 服务器端: 先启动一个服务器端的socket     ServerSocket svr = new ...

  7. Android开发代码规范

    目录 1.命名基本原则  2.命名基本规范 2.1编程基本命名规范 2.2分类命名规范 3.分类命名规范 3.1基本数据类型命名规范 3.2控件命名规范 3.3变量命名规范 3.4整个项目的目录规范化 ...

  8. 《samba服务搭建》RHEL6

    Samba服务不仅可以实现linux和win之间的文件共享,也可以实现linux和linux之间的共享,samba的用户只限服务端本地用户使用. 本文的环境是selinux开启的情况下配置 Samba ...

  9. FPGA笔记-读取.dat文件

    读取.dat图像文件 .dat文件是matlab生成的图像文件 initial begin // Initialize Inputs CLK = 0; RST = 1; IMAGE_DATA = 0; ...

  10. Spring MVC的启动过程

    一.概述 下面一个基本的运用springMVC的的web.xml的配置,这里要注意两个地方,一个是ContextLoadListener,一个是DispatcherServlet.web容器正是通过这 ...