Hunter | ||||||
| ||||||
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 | ||||||
2014暑假集训练习赛(8月13日) |
题目大意:
有一个N*M大的地图,其中标有-1的位子表示不能走,否则就是走到这个位子需要的花费。
(一个点重复走多次,也要重复花费);
现在主人公可以在任意一个边界的外边作为开始点进入(四个边的外边),一共有K个宝藏,他想要都带走。
问他最小时间花费是多少,从进入到拿到所有宝藏,再到出去(出去也要走到任意一个边界才算走出去);
如果有任意宝藏是拿不到的,输出0.
思路:
1、观察到K并不大,只有13的大小,那么我们肯定对于这部分的处理,套一个状压dp即可。
设定dp【i】【j】表示走完了状态为i的点,最终走到的点的编号是j的最小花费。
那么有:dp【i】【j】=min(dp【i】【j】,dp【l】【k】+dist【k】【j】);
这里要求i中包含j和k,l==i-(1<<j);
2、那么我们需要预处理出dist【i】【j】;
这里大家可以套一个优先队列跑Bfs.
也可以建图跑最短路,我选择建图跑最短路,那么很容易预处理出dist【i】【j】;
3、过程需要多维护一个从宝藏点到最近出口这一条路的长度。
过程维护一下细节处理好即可。
代码肯定很长,如果算法非常熟练的话,这种题是秒的。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct node
{
int from;
int to;
int next;
int w;
}e[505*505*20];
int head[505*505];
int dist[50][50];
int dis[505*505];
int vis[505*505];
int a[505][505];
int num[505][505];
int xx[505];
int yy[505];
int dp[(1<<16)][16];
int n,m,q,cont;
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
void Getmap()
{
cont=0;
memset(head,-1,sizeof(head));
int now=1;
for(int i=0;i<=30;i++)
{
for(int j=0;j<=30;j++)
{
dist[i][j]=0x3f3f3f3f;
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
num[i][j]=now++;
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]==-1)continue;
for(int k=0;k<4;k++)
{
int x=i+fx[k];
int y=j+fy[k];
if(x>=0&&x<n&&y>=0&&y<m&&a[x][y]!=-1)
{
add(num[i][j],num[x][y],a[x][y]);
}
}
}
}
}
void SPFA(int ss)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n*m;i++)dis[i]=0x3f3f3f3f;
dis[num[xx[ss]][yy[ss]]]=0;
queue<int >s;
s.push(num[xx[ss]][yy[ss]]);
while(!s.empty())
{
int u=s.front();
s.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
for(int z=0;z<q;z++)
{
if(z==ss)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(i==0||j==0||i==n-1||j==m-1)
{
dist[z][z]=min(dist[z][z],dis[num[i][j]]);
}
}
}
dist[z][z]+=a[xx[z]][yy[z]];
}
else
{
dist[ss][z]=dis[num[xx[z]][yy[z]]];
}
}
}
void Slove_bitDp()
{
int end=(1<<q);
for(int i=0;i<end;i++)
{
for(int j=0;j<q;j++)
{
dp[i][j]=0x3f3f3f3f;
}
}
for(int i=0;i<q;i++)
{
dp[(1<<i)][i]=dist[i][i];
}
for(int i=0;i<end;i++)
{
for(int j=0;j<q;j++)
{
if((i&(1<<j))!=0)
{
for(int k=0;k<q;k++)
{
if((i&(1<<k))!=0)
{
int l=i-(1<<j);
dp[i][j]=min(dp[i][j],dp[l][k]+dist[k][j]);
}
}
}
}
}
int output=0x3f3f3f3f;
for(int i=0;i<q;i++)
{
output=min(output,dp[end-1][i]+dist[i][i]-a[xx[i]][yy[i]]);
}
if(output==0x3f3f3f3f)printf("0\n");
else
printf("%d\n",output);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(num,-1,sizeof(num));
memset(a,0,sizeof(a));
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&a[i][j]);
}
}
scanf("%d",&q);
for(int i=0;i<q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
xx[i]=x;
yy[i]=y;
}
Getmap();
for(int i=0;i<q;i++)
{
SPFA(i);
}
Slove_bitDp();
}
}