【滚动数组】【状压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;
}
时间: 2024-10-11 17:05:33

【滚动数组】【状压dp】Gym - 100956F - Colored Path的相关文章

状压DP LIGHTOJ 1194 Colored T-Shirts

给你一串序列,求让这个序列相同的数字放在一起的最少交换次数 序列中的数字范围1-16 序列中数字个数1-1e5 思路: 首先要预处理 cnt[i][j] 表示数字j放在数字i前所要用到的交换次数 然后枚举每种情况1<<m 比如:m个零 000000000 第i个位置为0,表示此时数字i是乱序的,反之是放好的 代码如下 /******************************************** Author :Crystal Created Time : File Name :

LianLianKan HDU - 4272(状压dp)

题意:就是连连看,有两个相同的就能消除,再加上两个特别的规定,一是只能从栈顶开始消除,而是两个相同的元素之间距离不能超过6,询问能否消除序列中所有元素. 思路:数据水,贪心就能过,但严谨的考虑,贪心显然不能解决所有问题.这题虽然序列很长,但是状态并不复杂,可以使用滚动的状压dp,然后考虑使用多少位表示状态,每一种状态表示第i位为栈首的序列状态,该位前最多能消除掉该位后四位,所以我们只需要表示后9位的状态即可,总计10位. 某位上1表示该位已被消除,0表示未被消除. dp[i][j]表示从i位开始

Codeforces Gym 100676G Training Camp 状压dp

http://codeforces.com/gym/100676 题目大意是告诉你要修n门课,每门课有一个权值w[i], 在第k天修该课程讲获得k*w[i]的学习点数,给出了课程与先修课程的关系,要修该课程必须修完先修课程.问最多能学到多少点数. 非常简单的一道状压dp(一开始我还误导队友写成两维的去了 T^T); dp[s] : s 的二进制存放的是已经选择的课程,在该状态下的能获得的最大的点数. 这时如果再学一门课程k,将转移到状态ss (s | (1 << k) ) ,能否转移需要判断合

Codeforces Gym 100610 Problem K. Kitchen Robot 状压DP

Problem K. Kitchen Robot Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100610 Description Robots are becoming more and more popular. They are used nowadays not only in manufacturing plants, but also at home. One programmer wit

状压DP uvalive 6560

1 // 状压DP uvalive 6560 2 // 题意:相邻格子之间可以合并,合并后的格子的值是之前两个格子的乘积,没有合并的为0,求最大价值 3 // 思路: 4 // dp[i][j]:第i行j状态下的值 5 // j:0表示不合并,1表示向下合并 6 // 一开始输入要修改一下,然后滚动数组优化 7 8 #include <iostream> 9 #include <algorithm> 10 #include <cstring> 11 #include &

HDU 4906 Our happy ending (状压DP)

HDU 4906 Our happy ending 题目链接 题意:给定n个数字,每个数字可以是0-l,要选其中一些数字,然后使得和为k,问方案 思路:状压dp,滚动数组,状态表示第i个数字,能组成的数字状态为s的状态,然后每次一个数字,循环枚举它要选取1 - min(l,k)的多少,然后进行状态转移 代码: #include <cstdio> #include <cstring> typedef long long ll; const int N = (1<<20)

ZOJ3802 Easy 2048 Again (状压DP)

ZOJ Monthly, August 2014 E题 ZOJ月赛 2014年8月 E题 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5334 Easy 2048 Again Time Limit: 2 Seconds      Memory Limit: 65536 KB Dark_sun knows that on a single-track road (which means once he passed this

[hdu 4899]14年多校第四场C Hero meet devil 状压DP

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 122    Accepted Submission(s): 49 Problem Description There is an old country and the king fell in love with a devil. The devil always asks th

POJ 1038 状压DP

一个公司生产一种2*3规模的芯片,但是原材料上面有一些地方是不能用来当作芯片材料的,给出原料大小,及上面不能做原料的点,问你怎么分解,可以使生成芯片最大化. 对M进行三进制状压 last数组存储第i-1行和i-2行状态,cur数组存储i行和i-1行状态 cur[k]=2; // 本行k位置和上行k位置都不可用 cur[k]=1; // 本行k位置可用,上行k位置不可用 cur[k]=0; // 本行和上行位置k均可用 必须用滚动数组,否则爆内存 #include "stdio.h" #