题解 CF8C 【Looking for Order】

题意

坐标系中给定一个包的位置 \(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 就不放辣。

上一篇:运行打包后的文件步骤


下一篇:Floyd算法求每对顶点间最短路径(有向网)