問題の意味
n行m列の行列に、各列は循環的に任意の回数は、シフト後の各ラインを介して、最大Qの和の最大値をシフトさせることができます。
分析
各行の最大値と最大値は、任意にそれらの数および最大ように、各列に理解されるように選択します。
セット\(DP [I] [Sは ] \) フロント列iは、行セットが決定されたそのときにS、および最大値。答えは\(DP [M] [N( - << 1)-1] \)、
セット\(F [i]が[S] \)の最大値Sと同じ回数だけ循環シフトのセットのi番目の列の要素の後行の構成を選択するには、アウト前処理してもよいです。
列挙番号i + 1番目の列iは1列の要素(列挙サブセット)を認識解答選択肢を転送するために+変位。
転写式\(DP [I] [S ] = MAX(DP [I-1] [S '] + F [i]が[S-S']、DP [I] [S])、S 'はSでありますサブセット\) 。
複雑\(O(M *のTの*(2 ^ N * 2 ^ n個^のn + 3))\) 、明らかに、実際には、我々は選択ので、n列目の前に各列の最大の最大値を考慮するのみ必要としていませんでした使用されていない行n列目の他の列にあるいは劣ります。そのような複雑さにすることができる\(O(N-T *(2 * N-N- ^^ ^ N-2 + 3))\) 。
コード
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=1e5+10;
int t,n,m,a[15][2010],dp[15][1<<13],r[2010],b[2010],f[15][1<<13];
int cmp(int x,int y){
return r[x]>r[y];
}
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++) r[i]=0,b[i]=i;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%d",&a[i][j]);
r[j]=max(r[j],a[i][j]);
}
}
sort(b,b+m,cmp);
m=min(n,m);
for(int i=0;i<m;++i){
for(int j=0;j<(1<<n);++j){
int u=0;
for(int k=0;k<n;++k){
int ret=0;
for(int l=0;l<n;++l) if((j>>l)&1) ret+=a[(l+k)%n][b[i]];
u=max(u,ret);
}
f[i][j]=dp[i][j]=u;
if(i==0) continue;
for(int k=j;k;k=(k-1)&j) dp[i][j]=max(dp[i-1][k]+f[i][j-k],dp[i][j]);
}
}
printf("%d\n",dp[m-1][(1<<n)-1]);
}
return 0;
}