dp Vijos P1370 分苹果

来源:互联网 发布:网络市场调研的5个步骤 编辑:程序博客网 时间:2024/05/18 03:55

本来打算把隐式图USACO的三发莲花池全部都贴上来的但是到现在为止我的黄金莲花池还没有AC所以。。。再等等嗯!

计蒜客NOIP2017的模拟赛直接划水了。。说好的410呢(260葬送在了C语言上QAQ,讲道理这个题还不算难)

接下来开始dp吧!!!

来说说这题,有一些有意思的东西。


【问题描述】
 
  问题1:把 N 个同样的苹果放在 M 个同样的盒子,允许有的盒子空着不放,问共有多少种不同的分法? 


  问题2:把 N 个同样的苹果放在 M 个同样的盒子,不允许有的盒子空着不放,问共有多少种不同的分法? 


  注意:5,1,1和1,5,1是同一种放法。 
 
【输入格式】
 
  输入 N 和 M 。
 
【输出格式】
 
  两行:第一行为问题1的方案数,第二行为问题2的方案数,数据可能很大,输出模12345的结果。
 
【输入样例】
 
5 3
 
【输出样例】
 
5

 
【数据范围】
 
  1 <= M <= N <= 1000


分析:不难看出这是一个dp计算方案数的题,下面说说思路。

Q1:

f(i,j)表示在i个盒子里面放j个苹果,允许有盒子不放的方案数
f(i,j)=f(i-1,j)+f(i,j-i);
f(0,0)=1;
首先,盒子和苹果是没有区别的,意思就是我们求得的排列应当是有序的,否则就会出现重复计算方案数的情况(人为定序防止重算)。
解释一下这个方程:
首先f(i-1,j)很简单,即第一个盒子不放的情况。那么f(i,j-i)是什么情况?因为我们想要人为定序,那么就需要保证第一个盒子后面的所有盒子里面的苹果数量大于等于第一个盒子里面的数量,那么我们就在所有的盒子里面放上一个苹果,使得1变成0(归零思想)。然后我们就可以在所有的盒子都有一个苹果的基础上继续“允许有盒子不放”来计算方案数。注意这里的允许有盒子不
放是假的,只是把1视为0的基础上允许有盒子不放而已。


至于Q2,提供两种思路:
1、重新建立一个状态转移方程。
g(i,j)表示在i个盒子里面放j个苹果,不允许有盒子不放的方案数
g(i,j)=g(i-1,j-1)+g(i,j-i);
g(1,1)=1;
同样的,g(i-1,j-1)很好理解,g(i,j-i)也可以通过Q1提到的归零思想来解释。
2、直接使用f中的某个值来回答。
g(i,j)=f(i,j-i);


主要就是说说归零思想和人为定序的问题。


AC代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<cctype>#include<vector>using namespace std;const int maxn=1005;const int mo=12345;int N,M;int f[maxn][maxn];void dp(){f[0][0]=1;for(int i=1;i<=M;i++)for(int j=0;j<=N;j++){f[i][j]=f[i-1][j];if(j>=i) f[i][j]=(f[i][j]+f[i][j-i])%mo;}}int main(){freopen("test.in","r",stdin);freopen("test.out","w",stdout);scanf("%d%d",&N,&M);dp();printf("%d\n",f[M][N]);if(N>=M) printf("%d",f[M][N-M]);else printf("%d",0);return 0;}

原创粉丝点击