刚好做到easy,看hard也不是很难理解,就顺便做掉(当然,是参考别人的代码)。
题目链接:https://codeforces.com/contest/1209/problem/E2
题意:有n行m列的数组,每一列可以循环移动无数次,问每一行取一个数和最大是多少。
思路:状压dp,处理出min(m,n)列的每一个状态的最大值,然后dp。(easy的话可以直接写,复杂度是444*4)
其实状压dp也写了几题了,但总是感觉不得要领,遇到这题让我直接写的话估计要很久肯定写不出来 。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include <string>
using namespace std;
typedef long long ll;
struct S
{
int c[13],ma;
}a[2010];
int b[20][2020];
bool cmp(S a,S b)
{
return a.ma>b.ma;
}
int dp[20][(1<<12)+10],sum[20][(1<<12)+10];
int main()
{
int T,n,m,i,j,k,l;
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof dp);
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for (j = 1; j <= m; j++)
scanf("%d",&b[i][j]);
for(i=1;i<=m;i++)
{
a[i].ma=0;
for(j=1;j<=n;j++)
{
a[i].ma=max(a[i].ma,b[j][i]);
a[i].c[j]=b[j][i];
}
}
sort(a+1,a+1+m,cmp);
m=min(n,m);
for(i=1;i<=m;i++)
for(j=0;j<(1<<n);j++) {
int cc=0;
for(k=1;k<=n;k++)
{
int ans=0;
for(l=0;l<n;l++)
if(j>>((l+k)%n)&1)ans+=a[i].c[l+1];
cc=max(ans,cc);
}
sum[i][j]=cc;
}
for(i=1;i<=m;i++)
for(j=0;j<(1<<n);j++)
for(k=j;;k=(k-1)&j) {
dp[i][j] = max(dp[i][j], dp[i - 1][k] + sum[i][j ^ k]);//其实还是好理解的
if (!k)break;
}
printf("%d\n",dp[m][(1<<n)-1]);
}
}