题目简述:
一共有k元,存在两种票子,求从(1,1)开始,到(n,m)每个点上两种票子都用完,且将k元都用完的方案数。其中,第一种票子的费用为第二种票子的费用是-
,每次使用a票子可以从(i,j) - > (i+1,j),b票子可以从(i,j) - > (i,j+1)
思路:
显然,用于数据较小,可以设表示从点(x,y)开始,还剩l,r个票子,所以以得出两种方程。
买票子
乘车
但是数组开不到这么大,优化滚动一维数组,即每一个i&1,i+1 - > i&1^1,初始值
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 51 , M = 110 , mod = 998244353;
int n,m,a[N][N],b[N][N],k;
int f[2][46][46][46][91];
int add(int aa,int bb){
aa+=bb;
if(aa>mod) aa-=mod;
return aa;
}
signed main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>b[i][j];
f[1][1][0][0][0]=1;
for(int i=1;i<=n;i++,cout<<endl)
for(int j=1;j<=m;j++){
cout<<f[i&1][j][0][0][k]<<" ";
for(int x=0;x<=n-i;x++)
for(int y=0;y<=m-j;y++){
//买票
for(int w=0;w<=k;w++){
if(w+a[i][j]<=k&&f[i&1][j][x][y][w])
f[i&1][j][x+1][y][w+a[i][j]]=add(f[i&1][j][x+1][y][w+a[i][j]],f[i&1][j][x][y][w]);
}
}
for(int x=0;x<=n-i;x++)
for(int y=0;y<=m-j;y++){
//买票
for(int w=0;w<=k;w++){
if(w+b[i][j]<=k&&f[i&1][j][x][y][w])
f[i&1][j][x][y+1][w+b[i][j]]=add(f[i&1][j][x][y+1][w+b[i][j]],f[i&1][j][x][y][w]);
}
}
//乘车
for(int w=0;w<=k;w++){
int nowf=f[i&1][j][x][y][w];
if(!nowf) continue;
if(x) f[i&1^1][j][x-1][y][w]=add(f[i&1^1][j][x-1][y][w],nowf);
if(y) f[i&1][j+1][x][y-1][w]=add(f[i&1][j+1][x][y-1][w],nowf);
}
}
for(int x=0;x<=n-i;x++)
for(int y=0;y<=m-j;y++)
for(int w=0;w<=k;w++)
f[i&1][j][x][y][w]=0;
}
return 0;
}
文章描述了如何使用动态规划解决一个二维空间中,从起点到终点,利用两种不同类型的票子,每种票子有特定移动规则,且要求恰好用完k元的方案数计算问题。作者通过一维数组优化方法,实现递推求解过程。
465

被折叠的 条评论
为什么被折叠?



