牛客 - 收集纸片(最短哈密顿路径-状压dp)

题目链接:点击查看

题目大意:给出一个 n * m 的二维平面,其中有 k 个纸片,给出第一个纸片的位置,要求从第一个纸片出发,经过每个纸片一次后再回到第一个纸片的位置,输出最短路径

题目分析:最短哈密顿路径的模板题,比赛的时候为什么没看出来呢。。好像是被 n * m 很小所迷惑了,感觉像是一道搜索题,但想了半天没什么思路就不想做了,赛后回顾一下的时候发现,k 给的特别小,最大只有 11 ,而且题目的条件又完全符合哈密顿路径的性质,只不过要求起点和终点重合,那么我们只需要最后对每个状态维护一下到起点的最小值就好了

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
     
typedef long long LL;
    
typedef unsigned long long ull;
     
const int inf=0x3f3f3f3f;

const int N=1e5+100;

struct Point
{
	int x,y;
}point[15];

int d[15][15],dp[(1<<11)+100][15];

int dis(int x,int y)
{
	return abs(point[x].x-point[y].x)+abs(point[x].y-point[y].y);
}

int main()
{
#ifndef ONLINE_JUDGE
//    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
   	int w;
   	cin>>w;
   	while(w--)
   	{
   		int n,m;
   		scanf("%d%d",&n,&m);
   		scanf("%d%d",&point[0].x,&point[0].y);
   		int k;
   		scanf("%d",&k);
   		for(int i=1;i<=k;i++)
   			scanf("%d%d",&point[i].x,&point[i].y);
   		for(int i=0;i<=k;i++)
   			for(int j=0;j<=k;j++)
   				d[i][j]=dis(i,j);
   		memset(dp,inf,sizeof(dp));
   		dp[1][0]=0;
   		for(int i=0;i<(1<<k+1);i++)
   			for(int j=0;j<=k;j++)
   			{
   				if(dp[i][j]==inf)
   					continue;
   				if((i>>j)&1)
   				{
   					for(int t=0;t<=k;t++)
   					{
   						if((i>>t)&1)
   							continue;
   						dp[i|(1<<t)][t]=min(dp[i|(1<<t)][t],dp[i][j]+d[j][t]);
					}
				}
			}
		int ans=inf;
		for(int i=0;i<=k;i++)
			ans=min(ans,dp[(1<<k+1)-1][i]+d[0][i]);
		printf("The shortest path has length %d\n",ans);
	}
    
    
    
    
    
    
    
    
    
    
    
    
    
    return 0;
}
发布了655 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104453509
今日推荐