P9743 「KDOI-06-J」旅行

题目简述:

  一共有k元,存在两种票子,求从(1,1)开始,到(n,m)每个点上两种票子都用完,且将k元都用完的方案数。其中,第一种票子的费用为Aij第二种票子的费用是-Bij,每次使用a票子可以从(i,j) - > (i+1,j),b票子可以从(i,j) - > (i,j+1)

思路:

  显然,用于数据较小,可以设f[i][j][l][r][k]表示从点(x,y)开始,还剩l,r个票子,所以以得出两种方程。

                买票子f[i][j][l+1][r][k+a[i][j]]=\sum f[i][j][l][r][k];

                          f[i][j][l][r+1][k+b[i][j]]=\sum f[i][j][l][r][k]

                乘车f[i+1][j][l-1][r][k]=\sum f[i][j][l][r][k]

                       f[i][j+1][l][r-1][k]=\sum f[i][j][l][r][k]

但是数组开不到这么大,优化滚动一维数组,即每一个i&1,i+1  - >  i&1^1,初始值f[1][1][0][0][0]=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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值