洛谷 AT_abc180_e [ABC180E] Traveling Salesman among Aerial Cities 题解
由于 \(N\) 最大只有 \(17\),可以想到状压 dp。
因为遍历完所有点之后还要回到 \(1\),但是遍历所有的点的最优方案不一定是回到 \(1\) 的最优方案(有可能最后一个被遍历的点到 \(1\) 的距离很长),所以考虑加上一维表示最后一个被遍历的点。
于是状态表示就出来了。\(dp_{i,j}\) 表示已经被遍历的点的二进制表示集合为 \(i\),最后一个被遍历的点为 \(j\)。对于转移,枚举 \(i\) 中为 \(1\) 的 \(k(k\neq j)\),\(dp_{i,j}=min(dp_{i,j},dp_{i\oplus2^{j-1},k}+dis(j,k))\)。
最后枚举被遍历的最后一个点,加上最后一个点到 \(1\) 的距离,答案即为最小值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=20,INF=0x3f3f3f3f;
int n,dp[1<<N][N],ans=INF;
struct node
{
int x,y,z;
}a[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
memset(dp,0x3f,sizeof dp);
dp[1][1]=0;
for(int i=2;i<(1<<n);i++)
{
for(int j=1;j<=n;j++)
{
if(!(i&(1<<(j-1)))) continue;
for(int k=1;k<=n;k++)
{
if(k==j||!(i&(1<<(j-1)))) continue;
dp[i][j]=min(dp[i][j],dp[i^(1<<(j-1))][k]+abs(a[j].x-a[k].x)+abs(a[j].y-a[k].y)+max(0,a[j].z-a[k].z));
}
}
}
for(int i=2;i<=n;i++) ans=min(ans,dp[(1<<n)-1][i]+abs(a[1].x-a[i].x)+abs(a[1].y-a[i].y)+max(0,a[1].z-a[i].z));
printf("%d",ans);
return 0;
}

浙公网安备 33010602011771号