一个简单题,引发的思索 + 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\n",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\n",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\n",ans);
36     }
37     return 0;
38 }
posted on 2015-04-07 15:37  细雨微光  阅读(251)  评论(0编辑  收藏  举报