zoukankan      html  css  js  c++  java
  • pku ppt some problem

    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  ,其他行都可以由下面两条路取最大值。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mt(a,b) memset(a,b,sizeof(a))
     5 using namespace std;
     6 const int M=128;
     7 int n,a[M][M],dp[M][M];
     8 int dfs(int i,int j){
     9     if(~dp[i][j]) return dp[i][j];
    10     if(i==n) dp[i][j]=a[i][j];
    11     else     dp[i][j]=max(dfs(i+1,j),dfs(i+1,j+1))+a[i][j];
    12     return dp[i][j];
    13 }
    14 int main(){
    15     while(~scanf("%d",&n)){
    16         for(int i=1;i<=n;i++){
    17             for(int j=1;j<=i;j++){
    18                 scanf("%d",&a[i][j]);
    19             }
    20         }
    21         mt(dp,-1);
    22         printf("%d
    ",dfs(1,1));
    23     }
    24     return 0;
    25 }
    View Code

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

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mt(a,b) memset(a,b,sizeof(a))
     5 using namespace std;
     6 const int M=128;
     7 int a[M][M],dp[M][M];
     8 int main(){
     9     int n;
    10     while(~scanf("%d",&n)){
    11         for(int i=1;i<=n;i++){
    12             for(int j=1;j<=i;j++){
    13                 scanf("%d",&a[i][j]);
    14             }
    15         }
    16         mt(dp,0);
    17         for(int i=n+1;i>=1;i--){
    18             for(int j=1;j<=n;j++){
    19                 dp[i-1][j]=max(dp[i-1][j],dp[i][j]+a[i-1][j]);
    20                 dp[i-1][j-1]=max(dp[i-1][j-1],dp[i][j]+a[i-1][j-1]);
    21             }
    22         }
    23         printf("%d
    ",dp[1][1]);
    24     }
    25     return 0;
    26 }
    View Code

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

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=128;
     5 int dp[M][M];
     6 int main(){
     7     int n;
     8     while(~scanf("%d",&n)){
     9         for(int i=1;i<=n;i++){
    10             for(int j=1;j<=i;j++){
    11                 scanf("%d",&dp[i][j]);
    12             }
    13         }
    14         for(int i=n-1;i>=1;i--){
    15             for(int j=1;j<=i;j++){
    16                 dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+dp[i][j];
    17             }
    18         }
    19         printf("%d
    ",dp[1][1]);
    20     }
    21     return 0;
    22 }
    View Code

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

    记忆化搜索

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=1024;
     5 int n,a[M],dp[M];
     6 int dfs(int i){
     7     if(~dp[i]) return dp[i];
     8     dp[i]=1;
     9     for(int j=i+1;j<=n;j++){
    10         if(a[i]<a[j]){
    11             dp[i]=max(dp[i],dfs(j)+1);
    12         }
    13     }
    14     return dp[i];
    15 }
    16 int main(){
    17     while(~scanf("%d",&n)){
    18         for(int i=1;i<=n;i++){
    19             scanf("%d",&a[i]);
    20             dp[i]=-1;
    21         }
    22         int ans=0;
    23         for(int i=1;i<=n;i++){
    24             ans=max(ans,dfs(i));
    25         }
    26         printf("%d
    ",ans);
    27     }
    28     return 0;
    29 }
    View Code

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

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=1024;
     5 int a[M],dp[M];
     6 int main(){
     7     int n;
     8     while(~scanf("%d",&n)){
     9         for(int i=1;i<=n;i++){
    10             scanf("%d",&a[i]);
    11             dp[i]=1;
    12         }
    13         int ans=0;
    14         for(int i=1;i<=n;i++){
    15             for(int j=1;j<=i;j++){
    16                 if(a[j]<a[i]){
    17                     dp[i]=max(dp[i],dp[j]+1);
    18                 }
    19             }
    20             ans=max(ans,dp[i]);
    21         }
    22         printf("%d
    ",ans);
    23     }
    24     return 0;
    25 }
    View Code

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

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=1024;
     5 int a[M],dp[M];
     6 int main(){
     7     int n;
     8     while(~scanf("%d",&n)){
     9         for(int i=1;i<=n;i++){
    10             scanf("%d",&a[i]);
    11             dp[i]=1;
    12         }
    13         for(int i=1;i<=n;i++){
    14             for(int j=i+1;j<=n;j++){
    15                 if(a[i]<a[j]){
    16                     dp[j]=max(dp[j],dp[i]+1);
    17                 }
    18             }
    19         }
    20         int ans=0;
    21         for(int i=1;i<=n;i++){
    22             ans=max(ans,dp[i]);
    23         }
    24         printf("%d
    ",ans);
    25     }
    26     return 0;
    27 }
    View Code

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

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

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mt(a,b) memset(a,b,sizeof(a))
     5 using namespace std;
     6 const int M=512;
     7 char a[M],b[M];
     8 int dp[M][M];
     9 int main(){
    10     while(~scanf("%s%s",a,b)){
    11         mt(dp,0);
    12         int n=strlen(a);
    13         int m=strlen(b);
    14         for(int i=1;i<=n;i++){
    15             for(int j=1;j<=m;j++){
    16                 if(a[i-1]==b[j-1]){
    17                     dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
    18                 }
    19                 else{
    20                     dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
    21                 }
    22             }
    23         }
    24         printf("%d
    ",dp[n][m]);
    25     }
    26     return 0;
    27 }
    View Code

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

    二进制枚举,暴力。

     1 #include<cstdio>
     2 const int M=32;
     3 int a[M];
     4 int main(){
     5     int n;
     6     while(~scanf("%d",&n)){
     7         for(int i=0;i<n;i++){
     8             scanf("%d",&a[i]);
     9         }
    10         int all=1<<n,ans=0;
    11         for(int i=0;i<all;i++){
    12             int sum=0;
    13             for(int j=0;j<n;j++){
    14                 if((i>>j)&1) sum+=a[j];
    15             }
    16             if(sum==40) ans++;
    17         }
    18         printf("%d
    ",ans);
    19     }
    20     return 0;
    21 }
    View Code

     dfs枚举,暴力

     1 #include<cstdio>
     2 const int M=32;
     3 int a[M],ans,n;
     4 bool use[M];
     5 void dfs(int t){
     6     if(t==n){
     7         int sum=0;
     8         for(int i=0;i<n;i++){
     9             if(use[i]) sum+=a[i];
    10         }
    11         if(sum==40) ans++;
    12         return ;
    13     }
    14     use[t]=true;
    15     dfs(t+1);
    16     use[t]=false;
    17     dfs(t+1);
    18 }
    19 int main(){
    20     while(~scanf("%d",&n)){
    21         for(int i=0;i<n;i++){
    22             scanf("%d",&a[i]);
    23         }
    24         ans=0;
    25         dfs(0);
    26         printf("%d
    ",ans);
    27     }
    28     return 0;
    29 }
    View Code

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

     1 #include<cstdio>
     2 int a[32];
     3 int dfs(int sum,int k){///return 前k个物品选和为sum的情况
     4     if(sum==0) return 1;
     5     if(k<=0) return 0;
     6     return dfs(sum,k-1)+dfs(sum-a[k],k-1);
     7 }
     8 int main(){
     9     int n;
    10     while(~scanf("%d",&n)){
    11         for(int i=1;i<=n;i++){
    12             scanf("%d",&a[i]);
    13         }
    14         printf("%d
    ",dfs(40,n));
    15     }
    16     return 0;
    17 }
    View Code

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

     1 #include<cstdio>
     2 #include<cstring>
     3 #define mt(a,b) memset(a,b,sizeof(a))
     4 int a[32];
     5 int dp[32][64];
     6 int main(){
     7     int n;
     8     while(~scanf("%d",&n)){
     9         for(int i=1;i<=n;i++){
    10             scanf("%d",&a[i]);
    11         }
    12         mt(dp,0);
    13         dp[0][0]=1;
    14         for(int i=1;i<=n;i++){
    15             for(int j=0;j<=40;j++){
    16                 dp[i][j]+=dp[i-1][j];
    17                 if(j+a[i]<=40)
    18                 dp[i][j+a[i]]+=dp[i-1][j];
    19             }
    20         }
    21         printf("%d
    ",dp[n][40]);
    22     }
    23     return 0;
    24 }
    View Code

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

     1 #include<cstdio>
     2 #include<cstring>
     3 #define mt(a,b) memset(a,b,sizeof(a))
     4 int dp[64];
     5 int main(){
     6     int n,a;
     7     while(~scanf("%d",&n)){
     8         mt(dp,0);
     9         for(int i=1;i<=n;i++){
    10             scanf("%d",&a);
    11             for(int j=40;j>=1;j--){
    12                 if(dp[j]&&j+a<=40){
    13                     dp[j+a]+=dp[j];
    14                 }
    15             }
    16             dp[a]++;
    17         }
    18         printf("%d
    ",dp[40]);
    19     }
    20     return 0;
    21 }
    View Code

    end

  • 相关阅读:
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    类的封装和隐藏
    函数的装饰器
    vue嗯嗯
  • 原文地址:https://www.cnblogs.com/gaolzzxin/p/3970713.html
Copyright © 2011-2022 走看看