题意:
给定一个n*m的矩阵,每行最多取m/2个数,求取得的数的和的最大值,并且和能被k整除
很明显就是一个取与不取的背包问题,唯一个问题是每行的限制怎么实现,其实很简单,只要在一行结束的时候把取了其他个数的值全都归到0上,把限制重置掉就行
转移方程:dp[i][j][k]表示取到第i个格子(按行列顺序编号),本行取了j个数,目前模K的余数为k时取到的最大值
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][(k-a[i][j])%k]+a[i][j]);
下附代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int INF=0X3f3f3f3f; 6 int dp[4901][36][75],a[75][75]; 7 int n,m,k; 8 int ab(int x,int k){ 9 if (x>=0) return x%k; 10 else { 11 int ex=abs(x)/k+1; 12 return (x+ex*k)%k; 13 } 14 } 15 int main(){ 16 memset(dp,-1,sizeof(dp)); 17 scanf("%d%d%d",&n,&m,&k); 18 for (int i=1; i<=n; i++) 19 for (int j=1; j<=m; j++){ 20 scanf("%d",&a[i][j]); 21 } 22 dp[0][0][0]=0; 23 for (int i=1; i<=n; i++){ 24 for (int j=1; j<=m; j++){ 25 int now=(i-1)*m+j; 26 for (int p=0; p<=m/2; p++) 27 for (int t=0; t<k; t++) 28 dp[now][p][t]=dp[now-1][p][t]; 29 for (int p=m/2; p>=1; p--){ 30 for (int t=k-1; t>=0; t--){ 31 if (dp[now-1][p-1][ab(t-a[i][j],k)]!=-1) 32 dp[now][p][t]=max(dp[now][p][t],dp[now-1][p-1][ab(t-a[i][j],k)]+a[i][j]); 33 } 34 } 35 } 36 for (int j=m/2; j>=1; j--){ 37 for (int p=k-1; p>=0; p--){ 38 dp[i*m][0][p]=max(dp[i*m][0][p],dp[i*m][j][p]); 39 } 40 } 41 } 42 int res=0; 43 for (int i=0; i<=m/2; i++){ 44 res=max(res,dp[n*m][i][0]); 45 } 46 printf("%d ",res); 47 }