题目:
妞妞参加了Nowcoder Girl女生编程挑战赛, 但是很遗憾, 她没能得到她最喜欢的黑天鹅水晶项链。
于是妞妞决定自己来制作一条美丽的项链。一条美丽的项链需要满足以下条件:
1、需要使用n种特定的水晶宝珠
2、第i种水晶宝珠的数量不能少于li颗, 也不能多于ri颗
3、一条美丽的项链由m颗宝珠组成
妞妞意识到满足条件的项链种数可能会很多, 所以希望你来帮助她计算一共有多少种制作美丽的项链的方案。
题目分析:
我的想法是递归(刚刚有点递归的感觉,想起来也就是树形结构往后遍历,但是递归的资源占用超出要求内存了);看到有人用动态规划算法写的,我觉得很厉害,虽然想用动态规划,但是没想到状态转移公式,但是别人就能想到,我慢慢修炼学习吧,刷的题目太少了,以下是动态规划的代码(我觉得这个思路简直绝了):
链接:https://www.nowcoder.com/questionTerminal/e7e0230b12de4239a7f547a01d731522 来源:牛客网 #include<stdio.h> #include<string.h> const int maxn=100; #define max(a,b) a>b?a:b int n,m,a[maxn],l[maxn],r[maxn]; long long dp[maxn][maxn+1]; int main(){ int i,j,k; //freopen("input.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ for(i=0;i<n;i++) scanf("%d%d",l+i,r+i); memset(dp,0,sizeof(dp));//将动态数组全部置0 for(i=l[0];i<=r[0];i++) dp[0][i]=1;//当只用一种宝珠的时候,因为第一种只能用l[0]~r[0]颗,对应的是l[0]~r[0]颗宝珠的项链,前一种宝珠的方案都是1种。 for(i=1;i<n;i++) for(j=1;j<=m;j++){ int left=max(0,j-r[i]),right=max(0,j-l[i]);//这两个区间对应的是当前 前i种宝珠取多少个,最少取(j-r[i]),最多取(j-l[i]); for(k=left;k<=right;k++) dp[i][j]+=dp[i-1][k];那么这个区间就对应的前i-1宝珠在(j-l[i]~j-r[i])区间所有方案,其总和就对应的j个宝珠的项链用前i种宝珠的方案总数 } printf("%lld\n",dp[n-1][m]); } }//dp[i][j]表示用前i种宝石组成j颗宝石的项链的方案数 //但是第i种只能是l[i]到r[i]之间的数量 //所以dp[i][j]=dp[i-1][j-r[i]]+dp[i-1][j-r[i]+1]+...+dp[i-1][j-l[i]]
下面是我递归写的,有70%通过了,但是超出要求内存限制了。我的思路是从LeetCode上面的一个寻找一颗二叉树上的一段路径上元素之和等于target这个题目来的。
#include <iostream> #include <stdlib.h> #include <vector> using namespace std; int sum = 0; int n; void sumKind(int perls, int gap, vector<int> l,vector<int> r) { if (gap < 0) return;// if (perls == n - 1 &&gap > r[perls]) return; if (perls == n - 1 &&gap >= l[perls]&&gap <= r[perls]) { sum++; return; }//就是每找到一条方案路径就sum++ for (int i=l[perls];i<=r[perls];i++) { sumKind(perls + 1, gap - i, l, r);//第perls 种就再往后找第perls+1种对应的方案,直到这条路走不通,然后返回来,继续走下一个方案 } } int main() { int m; cin >> n>>m; vector<int> l(n, -1), r(n, -1); for (int i = 0;i<n;i++) { cin >> l[i] >> r[i]; } sumKind(0, m, l, r); cout << sum << endl; system("pause"); return 0; }