首页 > 代码库 > 【滚动数组】【状压dp】Gym - 100956F - Colored Path

【滚动数组】【状压dp】Gym - 100956F - Colored Path

技术分享

f(i,j,S)表示到(i,j),且经由的路径上的颜色集合为S的价值的最小值,从上方和左方转移过来即可。

要注意,内存不足,需要滚动数组优化,即使用了map,还是需要。

路径输出的时候,可以再跑一遍dp,这样就不用再开一个大数组了。

我的写法比较菜。卡了常数

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
int w[401][401],c[401][401];
typedef pair<int,int> Point;
map<int,int>f[401][401];
typedef pair<int,Point> data;
typedef map<int,int>::iterator ITER;
map<int,data>g[401][401];
int n,K,W;
int calc(int x)
{
	int res=0;
	while(x)
	  {
	  	res+=(x&1);
	  	x>>=1;
	  }
	return res;
}
Point path[1001];
int e;
int main()
{
	scanf("%d%d%d",&n,&K,&W);
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    scanf("%d",&w[i][j]);
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    scanf("%d",&c[i][j]);
	if(w[1][1]>W)
	  {
	  	puts("-1");
	  	return 0;
	  }
	f[1][1][1<<(c[1][1]-1)]=w[1][1];
	for(int i=1;i<=n;++i){
	  for(int j=1;j<=n;++j)
	    {
	      if(i>1 && j>1)
	        {
	          for(ITER it=f[i-1][j].begin();it!=f[i-1][j].end();++it)
	            {
	              int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j];
	              if(f[i][j].find(nS)==f[i][j].end())
	                {
	                  if(tmp<=W)
					    {
					      f[i][j][nS]=tmp;
					      g[i][j][nS]=data((*it).first,Point(i-1,j));
					    }
	                }
	              else if(f[i][j][nS]>tmp)
	                {
	                  f[i][j][nS]=tmp;
					  g[i][j][nS]=data((*it).first,Point(i-1,j));
	                }
	            }
	          for(ITER it=f[i][j-1].begin();it!=f[i][j-1].end();++it)
	            {
	              int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j];
	              if(f[i][j].find(nS)==f[i][j].end())
	                {
	                  if(tmp<=W)
					    {
					      f[i][j][nS]=tmp;
					  	  g[i][j][nS]=data((*it).first,Point(i,j-1));
					    }
	                }
	              else if(f[i][j][nS]>tmp)
	                {
	                  f[i][j][nS]=tmp;
					  g[i][j][nS]=data((*it).first,Point(i,j-1));
	                }
	            }
	        }
	      else if(i==1 && j>1)
	        {
	          for(ITER it=f[i][j-1].begin();it!=f[i][j-1].end();++it)
	            {
	              int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j];
	              if(f[i][j].find(nS)==f[i][j].end())
	                {
	                  if(tmp<=W)
					    {
					      f[i][j][nS]=tmp;
					  	  g[i][j][nS]=data((*it).first,Point(i,j-1));
					    }
	                }
	              else if(f[i][j][nS]>tmp)
	                {
	                  f[i][j][nS]=tmp;
					  g[i][j][nS]=data((*it).first,Point(i,j-1));
	                }
	            }
	        }
	      else if(i>1 && j==1)
	        {
	          for(ITER it=f[i-1][j].begin();it!=f[i-1][j].end();++it)
	            {
	              int nS=(*it).first|(1<<(c[i][j]-1)),tmp=(*it).second+w[i][j];
	              if(f[i][j].find(nS)==f[i][j].end())
	                {
	                  if(tmp<=W)
					    {
					      f[i][j][nS]=tmp;
					      g[i][j][nS]=data((*it).first,Point(i-1,j));
					    }
	                }
	              else if(f[i][j][nS]>tmp)
	                {
	                  f[i][j][nS]=tmp;
					  g[i][j][nS]=data((*it).first,Point(i-1,j));
	                }
	            }
	        }
	    }
	  if(i>=3)
	    {
	      for(int j=1;j<=n;++j)
	        {
	          f[i-2][j].clear();
//	          g[i-2][j].
			} 
	    }
	}
	int ans=2147483647;
	int anS;
	for(ITER it=f[n][n].begin();it!=f[n][n].end();++it)
	  {
	  	int tmp=calc((*it).first);
	  	if(tmp<ans)
	  	  {
	  	  	ans=tmp;
	  	  	anS=(*it).first;
	  	  }
	  }
	if(ans==2147483647)
	  puts("-1");
	else
	  {
	  	printf("%d\n",ans);
	  	data U=data(anS,Point(n,n));
	  	path[++e]=Point(n,n);
	  	while(U.second!=Point(1,1))
	  	  {
	  	  	U=g[U.second.first][U.second.second][U.first];
	  	  	path[++e]=U.second;
	  	  }
	  	for(int i=e;i>=1;--i)
	  	  printf("%d %d%c",path[i].first,path[i].second,i==1 ? ‘\n‘ : ‘ ‘);
	  }
	return 0;
}

【滚动数组】【状压dp】Gym - 100956F - Colored Path