• 一个简单题,引发的思索 + nyoj 1189


    题目描述:第一行:给你两个数m和n,m表示有m个数,然后下一行输入m个数,每个数只能选择一次,统计共有多少种情况使得所选数的和大于等于n;

    解决本题我想到了两种方法,(题目自己想的,先不考虑超时),第一种dfs(题目自己想的,先不考虑超时)第二种:01背包问题;

    dfs 由于递归的结束条件放错了导致最后结果中重复算了很多次,经过分析修改才得出结果;

    第一种方法代码:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 using namespace std;
     5 int  ans;
     6 int  a[50];
     7 int m , n;
     8 void dfs(int i,int sum)
     9 {
    10     if(i>=m)//一开始错了很久,写成了if(i>=m)  return ;后来发现次数变多了
    11     {
    12         if(sum>=n)
    13         {
    14             //printf("sum == %d
    ",sum);
    15             ans++;
    16         }
    17         return ;
    18     }
    19     dfs(i+1,sum); //
    20     dfs(i+1,sum+a[i+1]);//不要
    21 }
    22 int main()
    23 {
    24     while(cin>>m>>n)
    25     {
    26         ans = 0;
    27         for(int i = 1;i<=m; i++)
    28             scanf("%d",&a[i]);
    29         dfs(0,0);
    30         cout<<ans<<endl;
    31     }
    32     return 0;
    33 }

    第二种方法动态规划:状态转移方程  dp[i][j] = dp[i-1][j] + dp[i-1][j-a[i]];

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N = 100;
    int dp[N][N];
    int a[50];
    int m , n;
    int main()
    {
        while(cin>>m>>n)
        { int sum  = 0,ans = 0;
            for(int i = 1;i<=m; i++)
            {
                scanf("%d",&a[i]);
                sum = sum + a[i];
            }
           memset(dp,0,sizeof(dp));
           dp[0][0]  = 1;
           for(int i = 1; i<=m; i++)
           {
             for(int j = 0;j<=sum;j++)
            {
               dp[i][j] = dp[i-1][j]+dp[i-1][j-a[i]];
               //printf("i=%d  j=%d %d
    ",i,j,dp[i][j]);
            }
        }
        ans = 0;
        for(int i = n;i<=sum;i++)
            ans = ans +dp[m][i];
        printf("%d",ans);
        }
        return 0;
    }

    ny1189  题目描述:和上面的描述类似,只不过是把加号变成了 异或和而已,解题思想类似,数据量大,直接开辟数组,存不下,只能压缩,dfs必然会超时

    代码:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<cstring>
     5 using namespace std;
     6 const int N = 1100100;
     7 long long dp[3][N];
     8 long long a[50];
     9 int m , n;
    10 int main()
    11 {
    12     int ma;
    13     while(cin>>m>>n)
    14     { long long ma  = 0;
    15     memset(dp,0,sizeof(dp));
    16         for(int i = 1;i<=m; i++)
    17         {
    18             scanf("%lld",&a[i]);
    19             ma=max(ma,a[i]);//每次都存储最大的值
    20         }
    21        dp[0][0]  = 1;
    22        for(int i = 1; i<=m; i++)
    23        { memset(dp[i%2],0,sizeof(dp[i%2])); //只是用了两层的循环,这样很简单的减少了空间的用量
    24          for(int j = 0;j<=ma;j++)
    25         {
    26            dp[i%2][j^a[i]] = dp[(i+1)%2][j]+dp[i%2][j^a[i]];//
    27            dp[i%2][j] = dp[i%2][j] + dp[(i+1)%2][j];//不要
    28            if(ma<(j^a[i]))
    29               ma = (j^a[i]);
    30         }
    31     }
    32     long long ans = 0 ;
    33     for(int i = n;i<=ma;i++)
    34         ans = ans +dp[m%2][i];
    35     printf("%lld
    ",ans);
    36     }
    37     return 0;
    38 }
  • 相关阅读:
    LTE问题集锦(0)
    LTE问题集锦(3)
    LTE问题集锦(2)
    LTE问题集锦(1)
    LTE学习之路(9)—— 3GPP TS协议系列总结
    (原创)我的测试生涯(2)——《Clearcase UCM Practice》
    我的测试生涯(1)——开篇《Clearcase简介》
    (转载)十年、五年,你该做的事
    (转载)Windows消息机制
    LTE学习之路(8)——信令流程
  • 原文地址:https://www.cnblogs.com/lovychen/p/4398479.html
Copyright © 2020-2023  润新知