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. Exchange之准备AD及域

    1.         若有旧版本的Exchange 2003,则需要执行以下命令: setup.com /PrepareLegacyExchangePermissions 2.         准备架 ...

  2. redistribute and Suboptimal routing

    重分发和次优路由 基础环境 拓扑: 分别配置好基本的环境,包含ip地址,路由协议的启用,得到他们的路由表分别为 R1: R2: R3: R4: 1.      在R1上将eigrp和OSPF进行双向重 ...

  3. 4月12日学习笔记——jQuery操作属性和样式

    区分 DOM 属性和元素属性 <img src="images/image.1.jpg" id="hibiscus" alt="Hibiscus ...

  4. DFS入门之二---DFS求连通块

    用DFS求连通块也是比较典型的问题, 求多维数组连通块的过程也称为--“种子填充”. 我们给每次遍历过的连通块加上编号, 这样就可以避免一个格子访问多次.比较典型的问题是”八连块问题“.即任意两格子所 ...

  5. 3月3日(4) Remove Duplicates from Sorted List

    原题 Remove Duplicates from Sorted List 有序单链表去重,delete 只能对指针起作用. /** * Definition for singly-linked li ...

  6. DEDECMS中,会员中心的常用知识

    会员中心 引入了member/config.php,即可用$cfg_ml->fields['face'].$cfg_ml->fields['spacesta']等

  7. shell 字符截取

    Linux 的字符串截取很有用.有八种方法. 假设有变量 var=http://www.aaa.com/123.htm. # 读sharp 谐音 杀: ${var#*//} 杀掉//左边的,保留右边的 ...

  8. ERP基本功——物料的四个量

    ERP基本功——物料的四个量 在分析制造业管理问题的时候,如果能借用一些ERP里才会用到的概念,就会非常的简单,并且条理清晰. 我觉得柳中冈先生一再强调的一个观点非常有用,大意是这样的:任何人依据现有 ...

  9. git管理和自动部署项目

    当一个项目需要纳入到版本控制的时候,选择的工具还是比较多的,最常见的就是工具有CVS,SVN,GIT等.在平时的开发中视情况而定,从来就没有最好的版本控制工具,只有最适合的工具.在这里我习惯用git来 ...

  10. C#中gridView常用属性和技巧介绍

    .隐藏最上面的GroupPanel gridView1.OptionsView.ShowGroupPanel=false; .得到当前选定记录某字段的值 sValue=Table.Rows[gridV ...