程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 最短路+狀態壓縮dp(旅行商問題)hdu-4568-Hunter

最短路+狀態壓縮dp(旅行商問題)hdu-4568-Hunter

編輯:C++入門知識

題目大意:

給一個矩陣 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的花費。

對於已求出的每一種珠寶狀態更新後面未求出珠寶的狀態。

代碼:

 

<SPAN style="FONT-SIZE: 14px">#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\n",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\n",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\n",i,dp[i][lim-1]);
         ans=min(ans,dp[i][lim-1]+cost[i]); //從最短路走出去
      }

      printf("%d\n",ans);

   }

   return 0;
}

</SPAN>

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved