ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 CF8C 【Looking for Order】

2022-01-04 17:05:16  阅读:150  来源: 互联网

标签:状态 le dist 题解 物品 Looking 耗时 CF8C dp


题意

坐标系中给定一个包的位置 \(x_0,y_0\),有 \(n\) 个物品给定坐标 \(x_i,y_i\)。从一个点到另一个点的时间花费为两点间欧几里得距离的平方。你从包出发,每次最多拿 \(2\) 个物品,求把所有物品放到包里的最小耗时。

  • \(1\le n\le24,1\le x_i,y_i\le 100\),\(i\in[0,n]\)。

思路

看见数据范围立刻想到状压 dp。

考虑设 \(dp_{statu}\) 表示当前拿取物品的状态为 \(statu\) 时的最小耗时,其中 \(statu\) 的第 \(i\) 位为 \(0(1)\) 表示第 \(i\) 个物品没放到包里(放到包里)。

肉眼可见最终答案为 \(dp_{(11\cdots1)_2}\) 即 \(dp_{2^n-1}\)


考虑如何转移。

显然有 \(dp_0=0\),表示没开始拿不耗时。

其余的初始化为 inf 即可。

既然可以拿 \(2\) 个物品,就可以考虑在转移时枚举手里抓的两个物品 \(j,k\),用当前状态加上拿这两个物品的耗时更新拿了这两个物品的状态。好吧貌似有点绕

具体而言,先枚举当前状态 \(i\),再枚举 \(j,k\) 表示手里抓的物品,那么拿了 \(j,k\) 的状态就应该为 i|(1<<j-1)|(1<<k-1)注意判断当前状态不包含手里的物品,即 \(i\) 的第 \(j,k\) 位为 \(0\)。

为方便可以先初始化了 \(i,j\) 间的耗时,记为 \(dist_{i,j}\)

for(ll i=0;i<ss;i++){
	if(dp[i]<0x3f3f3f3f){
		for(ll j=1;j<=n;j++){
			if(((i>>(j-1))&1)==0){
				for(ll k=1;k<=n;k++){
					if(((i>>(k-1))&1)==0){//j,k 当前状态不能有
						nans=dp[i]+dist[0][j]+dist[j][k]+dist[k][0];
						if(dp[i|(1<<(j-1))|(1<<(k-1))]>nans){
							dp[i|(1<<(j-1))|(1<<(k-1))]=nans;
							pos[i|(1<<(j-1))|(1<<(k-1))]=i;
						}
					}
				}
				break;
			}
		}
	}
}

考虑如何输出路径。

根据套路,在转移的时候设一个 \(pos\) 表示状态转移来源,然后递归处理即可。

inline void print(ll now){
	if(now==0){
		return ;
	}
	cout<<"0 ";
	for(ll i=1;i<=n;i++){
		if(((now^pos[now])>>(i-1))&1){
			cout<<i<<" ";
		}//now^pos[now] 即为在这一轮转移过程中被新拿了的物品
	}
	print(pos[now]);
}

完整 code 就不放辣。

标签:状态,le,dist,题解,物品,Looking,耗时,CF8C,dp
来源: https://www.cnblogs.com/StarDust-lmy/p/15763109.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有