HDU 5067 Harry And Dig Machine 【状压DP】(TSP问题)

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=5067
在这里插入图片描述
★这是我做的第一道TSP题,TSP 即旅行商问题,简单来说就是有一个起点s,有n个要去的点,求 每个点都到达过且每个点只能到一次 最终回到起点s 所走过的最短路径 n比较少时,用状压DP即可~


翻译:

有一个n * m的区域,起点在左上角(1,1)点,n * m个点中,输入n * m的矩阵,大于0的点就是要到达的点。求 到达每个点一次 且最终回到原点 所经过的最短路程 即简单TSP问题


思路:

题目说了 要到达的点不超过 10个,那么当然可以用 状压DP解决~
①:找到这cnt个目的点,并求出他们各自之间的距离(横坐标之差的绝对值 加 纵坐标之差的绝对值)
②:dp[ i ] [ j ] 表示 状态 i 的最后一个点是 j 时的最短路程 (这时没有算回到原点的路程,最后加上就行)
③:状态转移方程:dp[i][j]=min(dp[i][j],dp[i^tmp][k]+dis[k][j]); (dis数组表示两点间的距离)
④:注意最后要小心 ans=inf (即一个目的点都没有的情况 我被这里卡了) 要ans=0处理

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<string>
using namespace std;
const int maxn=12;
const int sz=1<<11;
const int mod=1e9+7;
const int inf=2e9+7;
const double pi=3.1415926;
typedef long long LL;
int n,m;
struct node
{
    int x,y;
}f[maxn];
int dp[sz][maxn];
int dis[maxn][maxn];
template<class T>
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        int cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int x;
                read(x);
                if(x){
                    f[++cnt].x=i;
                    f[cnt].y=j;
                }
            }
        }
        for(int i=1;i<=cnt;i++){                  //目的点之间的距离
            for(int j=1;j<=cnt;j++){ 
                dis[i][j]=abs(f[i].x-f[j].x)+abs(f[i].y-f[j].y);
            }
        }
        int num=1<<cnt;
       memset(dp,0,sizeof dp);
        for(int i=0;i<num;i++){                 //TSP
            for(int j=1;j<=cnt;j++){
                int tmp=1<<j-1;
                if(i&tmp){
                    if(i==tmp) dp[i][j]=f[j].x+f[j].y-2;              //到原点的距离 后面也用到了
                    else{
                        dp[i][j]=inf;
                        for(int k=1;k<=cnt;k++){
                            if((i&(1<<k-1))&&k!=j){
                                dp[i][j]=min(dp[i][j],dp[i^tmp][k]+dis[k][j]);
                            }
                        }
                    }
                }
            }
        }
        int ans=inf;
        for(int i=1;i<=cnt;i++){
            ans=min(ans,dp[num-1][i]+f[i].x+f[i].y-2);                //加上 到原点的距离
        }
        if(ans==inf) ans=0;
        cout<<ans<<endl;
    }
    return 0;
}

发布了71 篇原创文章 · 获赞 89 · 访问量 8561

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/99008331