[GDOI2014]拯救莫莉斯

XXXV.[GDOI2014]拯救莫莉斯

因为\(nm\leq 50,m\leq n\)

所以\(m\)最大只会到\(7\),可以状压。

考虑设\(f[i][j][k]\)表示:

在前\(i-1\)行已经填好的情况下,第\(i-1\)行状态为\(j\),第\(i\)行状态为\(k\)的最小代价和最小数量(是个std::pair)。

转移时枚举\(i-2\)行的状态。复杂度\(O(n2^{3m})\)

代码:

#include<bits/stdc++.h>
using namespace std;
#define bp __builtin_popcount
#define pii pair<int,int>
#define x first
#define y second
#define mp make_pair
int n,m,c[100][100],lim,s[100][1<<8];
pii f[100][1<<8][1<<8],res=mp(0x3f3f3f3f,0x3f3f3f3f);
pii operator+(const pii &u,const pii &v){
	return mp(u.x+v.x,u.y+v.y);
}
bool che(int i,int j,int k){
	int jj=j;
	jj|=(j>>1)&(lim-1);
	jj|=(j<<1)&(lim-1);
	jj|=i;
	jj|=k;
	return jj==(lim-1);
}
int main(){
	scanf("%d%d",&n,&m),memset(f,0x3f3f3f3f,sizeof(f)),lim=(1<<m);
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++)scanf("%d",&c[i][j]);
		for(int j=0;j<lim;j++)for(int k=0;k<m;k++)if(j&(1<<k))s[i][j]+=c[i][k];
	}
	if(n==1){printf("%d %d\n",1,c[0][0]);return 0;}
	for(int i=0;i<lim;i++)for(int j=0;j<lim;j++)if(che(0,i,j))f[1][i][j]=make_pair(s[0][i]+s[1][j],bp(i)+bp(j));
	for(int i=2;i<n;i++)for(int j=0;j<lim;j++)for(int k=0;k<lim;k++)for(int l=0;l<lim;l++)if(che(l,j,k))f[i][j][k]=min(f[i][j][k],f[i-1][l][j]+mp(s[i][k],bp(k)));
	for(int i=0;i<lim;i++)for(int j=0;j<lim;j++)if(che(0,j,i))res=min(res,f[n-1][i][j]);
	printf("%d %d\n",res.y,res.x);
	return 0;
}

posted @ 2021-03-30 15:47  Troverld  阅读(45)  评论(0编辑  收藏  举报