[关闭]
@morehigh 2017-02-25T03:17:42.000000Z 字数 3280 阅读 1113

CQUPT 集训队专题训练(动态规划)

动态规划


A - 数位dp HDU - 2089
题意:

  1. nm0<nm<1000000)之间有多少个满足条件的数字
  2. 1.数字的每一位不含4
  3. 2.相邻两个组成的数不能是62

解题思路:

  1. dp[i][j]表示以j开头的i位数有多少个。首先将mn最大为7位数,初始化将满足条件的dp[i][j]求出来。
  2. 232为例子:sum232)=dp[3][1]+dp[2][1]+dp[2][2]+dp[1][1];求出区间(0,n)的sum(n),(0,m)的sum(m),用sum(m)-sum(n);

代码:

  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. using namespace std;
  6. int dp[10][10];
  7. void init()
  8. {
  9. memset(dp,0,sizeof(dp));
  10. dp[0][0]=1;
  11. for(int i=1;i<=7;i++)
  12. {
  13. for(int j=0;j<10;j++)
  14. {
  15. for(int k=0;k<10;k++)
  16. {
  17. if(j!=4&&!(j==6&&k==2))
  18. dp[i][j]+=dp[i-1][k];
  19. }
  20. }
  21. }
  22. }
  23. int solve(int n)
  24. {
  25. int dig[10];
  26. int len=0;
  27. while(n>0)
  28. {
  29. dig[++len]=n%10;
  30. n/=10;
  31. }
  32. dig[len+1]=0;
  33. int ans=0;
  34. for(int i=len;i;i--)
  35. {
  36. for(int j=0;j<dig[i];j++)
  37. {
  38. if(j!=4&&!(dig[i+1]==6&&j==2))
  39. ans+=dp[i][j];
  40. }
  41. if(dig[i]==4||dig[i]==2&&dig[i+1]==6)
  42. break;
  43. }
  44. return ans;
  45. }
  46. int main()
  47. {
  48. int l,r;
  49. while(scanf("%d%d",&l,&r)!=EOF&&l+r)
  50. {
  51. init();
  52. cout<<solve(r+1)-solve(l)<<endl;
  53. }
  54. return 0;
  55. }

B - 概率dp HDU - 4576
题意:

  1. 一个环形跑到,被分成n个格子并且将其1n进行标号,一个遥控汽车初始位置是1,在里面每发动一次,方向不确定的跑一次,发动m次求最后小车停在(lr)区间的概率为多少

解题思路:

  1. 每次发动要么顺时针跑要么逆时针跑,概率各是0.5,每移动一次两边概率格子原来的概率+移动之前格子的概率*0.5.最后将lr之间的格子的概率相加

代码:

  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. using namespace std;
  6. double pre[210],now[210];
  7. int main()
  8. {
  9. int n,l,m,r;
  10. while(scanf("%d%d%d%d",&n,&m,&l,&r)!=EOF&&n+m+l+r)
  11. {
  12. int w;
  13. memset(pre,0,sizeof(pre));
  14. memset(now,0,sizeof(now));
  15. pre[0]=1;
  16. for(int i=0;i<m;i++)
  17. {
  18. scanf("%d",&w);
  19. for(int j=0;j<n;j++)
  20. {
  21. if(pre[j])
  22. {
  23. now[(j+w)%n]+=pre[j]*0.5;
  24. now[((j-w)+n)%n]+=pre[j]*0.5;
  25. }
  26. }
  27. for(int j=0;j<n;j++)
  28. {
  29. pre[j]=now[j];
  30. now[j]=0;
  31. }
  32. }
  33. double ans=0;
  34. for(int i=l-1;i<r;i++)
  35. {
  36. ans+=pre[i];
  37. }
  38. printf("%.4lf\n",ans);
  39. }
  40. return 0;
  41. }

C - 区间dp POJ - 1160
题意:

  1. v个村子在一条直线上,准备把p个邮局建在p个村子中,需要使每个村子到离他最近的邮局距离和最小,求最小的距离

解题思路:

  1. dp[j][i]指的是在前j个村子建i个邮局距离和最小。首先在ab村子建一个邮局的距离之和最小,应该把邮局建在(a+b)/2村子,设a=1,b=4,sum[a][b]=a[2]-a[1]+a[3]-a[2]+a[4]-a[2]=a[3]-a[1]+a[4]-a[2],当b=5时,sum[a][b]=sum[a][b-1]+a[b]-a[(a+b)/2], dp[v][p]为距离和最小
  2. 状态转移方程:dp[j][i]=min(dp[j][i],dp[k][i-1]+sum[k+1][j]);

代码:

  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. #define inf 0xfffffff
  6. using namespace std;
  7. int dp[310][50];
  8. int sum[310][310];
  9. int a[310];
  10. int main()
  11. {
  12. int v,p;
  13. while(scanf("%d%d",&v,&p)!=EOF)
  14. {
  15. for(int i=1;i<=v;i++)
  16. scanf("%d",&a[i]);
  17. memset(sum,0,sizeof(sum));
  18. for(int i=1;i<=v;i++)
  19. {
  20. for(int j=i+1;j<=v;j++)
  21. {
  22. sum[i][j]=sum[i][j-1]-a[(i+j)/2]+a[j];
  23. }
  24. }
  25. for(int i=1;i<=v;i++)
  26. {
  27. dp[i][1]=sum[1][i];
  28. dp[i][i]=0;
  29. }
  30. for(int i=2;i<=p;i++)
  31. {
  32. for(int j=i;j<=v;j++)
  33. {
  34. dp[j][i]=inf;
  35. for(int k=i-1;k<j;k++)
  36. {
  37. dp[j][i]=min(dp[j][i],dp[k][i-1]+sum[k+1][j]);
  38. }
  39. }
  40. }
  41. printf("%d\n",dp[v][p]);
  42. }
  43. return 0;
  44. }

E - 完全背包
题意:

  1. 输入数据有多组,对于每组数据第一行输入nmks(0 < n,m,k,s < 100)四个正整数。分别表示还需的经验值,保留的忍耐度,怪的种数和最多的杀怪数。接下来输入k行数据。每行数据输入两个正整数ab(0 < a,b < 20);分别表示杀掉一只这种怪xhd会得到的经验值和会减掉的忍耐度。(每种怪都有无数个)

解题思路:

  1. dp[i][j]表示忍耐度为i,杀怪数为j时所得的经验值,由于每只怪可以杀多次,所以状态转移方程: dp[i][j]=max(dp[i][j],dp[i-cnt*monst[l].na][j-cnt]+monst[l].val*cnt);
  2. cnt指的是打这种怪的次数

代码:

  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. #define mod 10000
  6. using namespace std;
  7. int dp[110][110];
  8. struct Node
  9. {
  10. int na,val;
  11. }monst[110];
  12. int main()
  13. {
  14. int n,m,k,s;
  15. while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF)
  16. {
  17. for(int i=0;i<k;i++)
  18. {
  19. scanf("%d%d",&monst[i].val,&monst[i].na);
  20. }
  21. memset(dp,0,sizeof(dp));
  22. int i;
  23. for(i=1;i<=m;i++)
  24. {
  25. for(int l=0;l<k;l++)
  26. {
  27. for(int j=1;j<=s;j++)
  28. {
  29. int cnt=1;
  30. while(cnt*monst[l].na<=i&&cnt<=j)
  31. {
  32. dp[i][j]=max(dp[i][j],dp[i-cnt*monst[l].na][j-cnt]+monst[l].val*cnt);
  33. cnt++;
  34. }
  35. }
  36. }
  37. if(dp[i][s]>=n)
  38. break;
  39. }
  40. if(i>m)
  41. printf("-1\n");
  42. else
  43. {
  44. printf("%d\n",m-i);
  45. }
  46. }
  47. return 0;
  48. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注