题目
m个50kg的和n个100kg的一群人要过河,有且仅有一条可载重量为k的船,请问最少多少次渡河全部渡过去。
思路
值得深思的一道线性DP题目
通过杨辉三角形可以快速求出组合数,进一步则有A[a][b][c][d]=从a个人中选择c个人,同时在b个人中选择d个人可能的方案。确定状态dp[i][j][k] 表示第i个行程,起点处有j个50kg的人,k个100kg的人。
状态转移方程运过去的转移方程
dp[i][x-a][y-b]+=A[x][y][a][b]*dp[i-1][x][y])%=Mod; 减少a个50,b个100
运回来
(dp[i+1][x+a][y+b]+=A[X-x][Y-y][a][b]*dp[i][x][y])%=Mod;增加a个50,b个100
#include<bits/stdc++.h>
#define Mod 1000000007
const int M=55;
long long dp[M*4][M][M],C[M][M],A[M][M][M][M];
int main(){
for(int i=0;i<M;++i) for(int j=C[i][0]=1;j<=i;++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod;
for(int a=0;a<M;++a) for(int b=0;b<M;++b) for(int c=0;c<=a;++c) for(int d=0;d<=b;++d) A[a][b][c][d]=C[a][c]*C[b][d]%Mod;
int n,k,X=0,Y=0;
scanf("%d %d",&n,&k);
for(int i=0,a;i<n;++i) scanf("%d",&a),++(a==50?X:Y);
dp[0][X][Y]=1;
for(int i=1;i<=4*n+1;i+=2){
long long res=0;
//运过来
for(int x=0;x<=X;++x) for(int y=0;y<=Y;++y) if(dp[i-1][x][y]){
for(int a=0;a<=x;++a) for(int b=0;b<=y;++b) if((a|b) && a*50+b*100<=k){
(dp[i][x-a][y-b]+=A[x][y][a][b]*dp[i-1][x][y])%=Mod;
}
}
if(dp[i][0][0]) return printf("%d\n%lld\n",i,dp[i][0][0]),0;
//运回去
for(int x=0;x<=X;++x) for(int y=0;y<=Y;++y) if(dp[i][x][y]){
for(int a=0;a<=X-x;++a) for(int b=0;b<=Y-y;++b) if((a|b) && a*50+b*100<=k){
(dp[i+1][x+a][y+b]+=A[X-x][Y-y][a][b]*dp[i][x][y])%=Mod;
}
}
}
puts("-1\n0");
return 0;
}