hdu4568Hunter(BFS+TSP)

Hunter

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 725    Accepted Submission(s): 200


Problem Description
  One day, a hunter named James went to a mysterious area to find the treasures. James wanted to research the area and brought all treasures that he could.
  The area can be represented as a N*M rectangle. Any points of the rectangle is a number means the cost of research it,-1 means James can't cross it, James can start at any place out of the rectangle, and explore point next by next. He will move in the rectangle and bring out all treasures he can take. Of course, he will end at any border to go out of rectangle(James will research every point at anytime he cross because he can't remember whether the point are researched or not).
  Now give you a map of the area, you must calculate the least cost that James bring out all treasures he can take(one point up to only one treasure).Also, if nothing James can get, please output 0.
 

Input
  The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case begins with a line containing 2 integers N M , (1<=N,M<=200), that represents the rectangle. Each of the following N lines contains M numbers(0~9),represent the cost of each point. Next is K(1<=K<=13),and next K lines, each line contains 2 integers x y means the position of the treasures, x means row and start from 0, y means column start from 0 too.
 

Output
  For each test case, you should output only a number means the minimum cost.
 

Sample Input
2 3 3 3 2 3 5 4 3 1 4 2 1 1 1 3 3 3 2 3 5 4 3 1 4 2 2 1 1 2 2
 

Sample Output
8 11
 

Source
 

Recommend
zhoujiaqi2010
 

Statistic | Submit | Discuss | Note

剛看到這道題時,我是立馬就想到了BFS,因爲是圖和最短路的結合,這時候用BFS準沒錯。

但是我就着BFS的常規思路想下去想了一天。沒有任何結果。。。

後來看了一下最小的數字是n,就是寶藏的點數纔到13,我就知道突破點在這裏了。。

後來總結,一般看到一道題當自己完全沒思路時,可以按題目最小的數字想。突破點一定在這裏,特別是動態規劃題。。

然後就把每個節點的最短路徑求出來。然後那200*200的迷宮地圖對於我們就沒用了。

我們只需要是點與點的最短路徑。

然後就是有13個點的TSP問題了(外面算一個點)

但是悲哀的是,用BFS把沒兩個節點最短路徑求出來之後就不會做了,如果是枚舉 O(N !)複雜度就絕對超時。

然後就上網找TSP的高效解法。選中了動態規劃。

後來只能將TSP動態規劃的模板原封不動地抄下來。。。

終於A了。

動態規劃方程解釋:

        假設從頂點s出發,令d(i, V’)表示從頂點i出發經過V’(是一個點的集合)中各個頂點一次且僅一次,最後回到出發點s的最短路徑長度。

        推導:(分情況來討論)

        ①當V’爲空集,那麼d(i, V’),表示從i不經過任何點就回到s了,如上圖的 城市3->城市0(0爲起點城市)。此時d(i, V’)=Cis(就是 城市i 到 城市s 的距離)、

        ②如果V’不爲空,那麼就是對子問題的最優求解。你必須在V’這個城市集合中,嘗試每一個,並求出最優解。

           d(i, V’)=min{Cik +  d(k, V’-{k})}

           注:Cik表示你選擇的城市和城市i的距離,d(k, V’-{k})是一個子問題。

        綜上所述,TSP問題的動態規劃方程就出來了:

         image

dp[i][j]的解釋:i是一種狀態如:i=3 則i爲00000000000011,就是說只有點一和點二在集合中。那這樣就可以表示V’這個集合了。。。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
int path[202][202];
int f[202][202],flag[202][202];
int minpath[15][15];
int dir[][2] = {{-1,0},{0,-1},{1,0},{0,1}};
int row,col;
int n;
int pf[15];
int dp[1<<16][20];
struct node
{
	int x;
	int y;
	int min;
	bool operator < (const node& a) const
	{
		return min>a.min;
	}
};
struct node1
{
	int x;
	int y;
}node1[20];
int Min(int a,int b)
{
	return a>b?b:a;
}
void BFS(int x,int y,int num)
{
	memset(flag,0,sizeof(flag));
	priority_queue<node> pq;
	while(!pq.empty())
		pq.pop();
	struct node nn,var;
	nn.x = x;
	nn.y = y;
	nn.min = 0;
	pq.push(nn);
	flag[x][y] = 1;
	while(!pq.empty())
	{
		nn = pq.top();
		pq.pop();
		if(f[nn.x][nn.y]>0)
		{
			int i = f[nn.x][nn.y];
			minpath[num][i] = nn.min;
			pf[num]++;
		}
		if(minpath[num][0]==-1 && (nn.x==1 || nn.x==row || nn.y==1 || nn.y==col))
		{
			minpath[num][0] = nn.min;
			minpath[0][num] = nn.min+path[x][y];
			pf[num]++;
		}
		if(pf[num]>n )
			return ;
		for(int j=0;j<4;j++)
		{
			int xx = nn.x+dir[j][0];
			int yy = nn.y+dir[j][1];
			if(path[xx][yy]!=-1 && flag[xx][yy]==0)
			{
				var.min = nn.min+path[xx][yy];
				var.x = xx;
				var.y = yy;
				pq.push(var);
				flag[xx][yy] = 1;
			}
		}
	}
}
int main()
{
	int T,i,j;
	scanf("%d",&T);
	while(T--)
	{
		memset(path,-1,sizeof(path));
		memset(f,0,sizeof(f));
		memset(minpath,-1,sizeof(minpath));
		scanf("%d%d",&row,&col);
		for(i=1;i<=row;i++)
			for(j=1;j<=col;j++)
			scanf("%d",&path[i][j]);
		
			scanf("%d",&n);
			for(i=1;i<=n;i++)
			{
				scanf("%d%d",&node1[i].x,&node1[i].y);
				node1[i].x++;
				node1[i].y++;
				f[node1[i].x][node1[i].y] = i;
			}
		memset(pf,0,sizeof(pf));
		for(i=1;i<=n;i++)
			BFS(node1[i].x,node1[i].y,i);  //每次求出node1[i]和其他點的最短距離,包括出去的最短距離

		memset(dp,0x3f,sizeof(dp));
		minpath[0][0] = 0;
        if(!n) {printf("0\n");continue;}
 
        for( i=0;i<=n;i++)					//這裏到下面都是套用別人的模板
        {
            dp[1<<i][i]=minpath[0][i];      //自己對TSP的動態規劃不熟,不能自己寫~~~
        }
		int end=(1<<(n+1));
        for( i=0;i<end;i++)
        {
            for( j=0;j<=n;j++)
            {
                if((i>>j)&1)  //滿足j要在i狀態裏面
                {
                    for(int k=0;k<=n;k++)
                    {
                        if((i>>k)&1)  //滿足k要在i狀態裏面
                        {
                            dp[i][j]=Min(dp[i][j],dp[i&(~(1<<j))][k]+minpath[k][j]);
                        }
                    }
                }
            }
        }
        printf("%d\n",dp[end-1][0]);

		
	}
	return 0;
}





發佈了58 篇原創文章 · 獲贊 89 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章