zoukankan      html  css  js  c++  java
  • 最短路+状态压缩dp(旅行商问题)hdu-4568-Hunter

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4568

    题目大意:

    给一个矩阵 n*m (n m<=200),方格里如果是0~9表示通过它时要花费的代价,-1表示不能通过它。

    矩阵中有k(k<=13)个珠宝,问从任意外边框出发取走所有珠宝并求走出矩阵的最小的代价。

    解题思路:

    先dij预处理每一个珠宝到其他其他珠宝的最小花费,不包括自己的花费。然后就是裸的TSP问题了,状态压缩dp即可。

    dp[i][j]表示最后到达第i个珠宝,且访问珠宝的状态为j时,最小的花费。

    dd[i][j]表示珠宝i到珠宝j之间的花费,注意此时包括j的花费不包括i的花费。

    对于已求出的每一种珠宝状态更新后面未求出珠宝的状态。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #define eps 1e-6
    #define INF 0x1f1f1f1f
    #define PI acos(-1.0)
    #define ll __int64
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    /*
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    */
    struct Node
    {
       int id,dis;
       //Node(){}
       Node(int x,int y)
       {
          id=x,dis=y;
       }
       friend bool operator <(const struct Node &a,const struct Node &b)
       {
          return a.dis>b.dis; //按距离从小到达排序,便于优先队列找到距离当前宝藏的最小距离
       }
    };
    #define Maxn 220
    int dd[20][20];//两个宝藏之间的距离
    int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
    int istr[Maxn][Maxn]; //表示珠宝的标号
    int sa[Maxn][Maxn],cost[20];//cost[i]表示i宝藏到边界的最短距离
    int n,m,k,hash[20],dp[20][1<<15];
    
    int tmpdis[Maxn*Maxn];//其他宝藏距离当前宝藏的距离
    bool vis[Maxn][Maxn];
    
    bool isbor(int x,int y) //是否为边界
    {
       if(x==0||x==n-1||y==0||y==m-1)
          return true;
       return false;
    }
    
    bool iscan(int x,int y) //是否在矩阵内部
    {
       if(x<0||x>=n||y<0||y>=m)
          return false;
       return true;
    }
    
    void dij(int hh,int cur) //迪杰斯特拉算法求
    {
       memset(tmpdis,INF,sizeof(tmpdis));
       memset(vis,false,sizeof(vis));
       vis[hh/m][hh%m]=true;
    
       priority_queue<Node>myq;
       tmpdis[hh]=0;
       myq.push(Node(hh,0));
    
       while(!myq.empty())
       {
          Node tmp=myq.top(); //把距离当前宝藏距离最小的位置找到
          myq.pop();
    
          int tt=tmp.id;
          int x=tt/m,y=tt%m;
    
          if(isbor(x,y)) //如果是边界,更新边界
             cost[cur]=min(cost[cur],tmp.dis);
          if(istr[x][y]!=-1) //如果是其他珠宝,更新两珠宝之间的距离
             dd[cur][istr[x][y]]=tmp.dis;
          for(int i=0;i<4;i++) //能走
          {
             int xx=x+dir[i][0],yy=y+dir[i][1];
             if(!iscan(xx,yy)||vis[xx][yy])
                continue;
             if(sa[xx][yy]==-1)
                continue;
             vis[xx][yy]=true;
             int temp=xx*m+yy;
             tmpdis[temp]=min(tmpdis[temp],tmp.dis+sa[xx][yy]);
             myq.push(Node(temp,tmpdis[temp]));
    
          }
       }
    }
    int main()
    {
       int t,a,b;
    
       scanf("%d",&t);
       while(t--)
       {
          scanf("%d%d",&n,&m);
          for(int i=0;i<n;i++)
             for(int j=0;j<m;j++)
                scanf("%d",&sa[i][j]);
          scanf("%d",&k);
          memset(istr,-1,sizeof(istr));
          for(int i=0;i<k;i++)
          {
             scanf("%d%d",&a,&b);
             istr[a][b]=i;
             hash[i]=a*m+b;  //将坐标从二维转化成一维便于处理
          }
          memset(dd,INF,sizeof(dd));
          for(int i=0;i<k;i++) //求出每一个宝藏到其他宝藏的距离
          {
             cost[i]=INF;
             dd[i][i]=0; //宝藏从自己到自己距离为0
             dij(hash[i],i);  //找到从i到所有的宝藏的最短距离
             //printf("i:%d cost:%d
    ",i,cost[i]);
          }
          memset(dp,INF,sizeof(dp));
          for(int i=0;i<k;i++)
          { //dp[i][1<<i]是包括i本身花费的,+进来花费cost[i]
             dp[i][1<<i]=cost[i]+sa[hash[i]/m][hash[i]%m];
            // printf("i:%d dp[i][1<<i]:%d
    ",i,dp[i][1<<i]);
          }
          int lim=1<<k;
          for(int i=0;i<lim;i++)
          {
             for(int j=0;j<k;j++)
             {
                if(!(i&(1<<j))) //如果没有经过第j个珠宝
                   continue;
                if(dp[j][i]==INF) //此状态无效
                   continue;
                for(int p=0;p<k;p++)
                {
                   if(i&(1<<p)) //p没有经过
                      continue;
                   if(dd[j][p]==INF)
                      continue;  //最后经过的变成了p 依据j->p 更新后面的状态
                   dp[p][i|(1<<p)]=min(dp[p][i|(1<<p)],dp[j][i]+dd[j][p]);
                }//dp[j][i]是已经求得的状态了
             }
          }
          int ans=INF;
          for(int i=0;i<k;i++)
          {
            // printf("%d %d
    ",i,dp[i][lim-1]);
             ans=min(ans,dp[i][lim-1]+cost[i]); //从最短路走出去
          }
    
          printf("%d
    ",ans);
    
       }
    
       return 0;
    }
    
    


  • 相关阅读:
    在C#中internal、protected internal关键字是什么意思?
    JScript版CollectionBase类的一个实现
    js继承的4种方法
    ASP删除文章时,需要删除eWebEditor上传文件
    Sql Server 2005中的架构(Schema)、用户(User)、登录(Login)和角色(Role)
    js绘图研究(一)
    JavaScript中this关键字使用方法详解
    SQL SERVER中架构的理解
    利用 wz_jsgraphics.js 画线
    js种4种继承法的优缺点
  • 原文地址:https://www.cnblogs.com/james1207/p/3260278.html
Copyright © 2011-2022 走看看