题目描述:第一行:给你两个数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 }