原题:
Hunter
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 958 Accepted Submission(s): 269
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.
![](https://i-blog.csdnimg.cn/blog_migrate/0f3257bc5d888f8c799eb1c5e99e8ed5.jpeg)
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
8 11
题意+题解:
一道需要先建图的TSP+状压问题。
经测试没有宝藏本身就不能走,或者两个宝藏之间被-1隔开不能想通的情况也不存在。如果都考虑到的话就需要写的再复杂些,先判断最大能取的个数和是哪些点,然后剩下的不能一次取到的数量较少的宝藏就直接舍去,再建图。
先做一遍BFS,或者SPFA也行,在map里搜索,加一个起点(终点),求出每个宝藏和起点之间的最短路。
这里从点a到点b的边,要计算b点的权值,而不计算a的权值,如果从b到a,则反之。因为TSP保证每个宝藏都有一个入度一个出度,所以宝藏该点的权值只被计算一次,所以就设置成这种起点不计算,终点计算的方法,防止重复计算。
BFS搜的话用优先队列,所有的结点只会入队列一次,比较快。
SPFA的话用标记减少入队列的次数也可以减少时间复杂度。
建好图后得到任意两点的距离,原图就可以丢掉了。下面就是TSP的问题了
一共有14个点(带虚拟的起点),状压开2^14-1就够了
dp[i][j] 表示 在状态i的情况下(这里i是一个二进制数,其中第k位为1的表示第k个结点已被遍历,0表示未被遍历),以j号结点为结束时的最小花费。
dp[i][j] = min(dp[i][j] , dp[i-(1<<j)][s] + dis(s,j)); 表示在i中去掉j结点时,以s结点结尾的dp值+s到j的距离 的最小值
最后输出 dp[(1<<(k+1))-1][k] 其中k为虚拟的起点和终点,一共有0---k-1号宝藏
之前写了一个SPFA建图,标号是1--k的代码,给写残了,也给贴出来吧
代码:
//大二寒假集训 第一章DP G_Hunter
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<functional>
#define MAXN 99999999
using namespace std;
typedef struct MyStruct
{
int x,y;
}Treasure;
typedef struct MyStruct1
{
int x,y,cost;
bool operator <(const MyStruct1 &a) const
{
return a.cost < cost;
}
}POINT;
Treasure point[15];
int map[210][210];
int dis[15][15];
int n,m,k;
int dp[17000][15];
int cost[210][210];
int add[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
bool vis[210][210];
bool flag[210][210];
void bfs_que(int num)
{
memset(vis,0,sizeof(vis));
int i,j,go_out=MAXN,flag_out=0,count=0;
for ( i = 0; i <=n ; i++)
for ( j = 0; j <=m ; j++)
cost[i][j]=MAXN;
POINT temp,newd;
temp.x=point[num].x;
temp.y=point[num].y;
temp.cost=0;
vis[temp.x][temp.y]=1;
priority_queue<POINT>Q;
Q.push(temp);
while (!Q.empty())
{
if(count==k)break;
temp=Q.top();
Q.pop();
if(temp.x==0 || temp.x==n-1 || temp.y==0 || temp.y==m-1)
{
if(!flag_out)
{
flag_out=1;
count++;
go_out=temp.cost;
}
}
for ( i = 0; i <4 ; i++)
{
newd=temp;
newd.x+=add[i][0];
newd.y+=add[i][1];
if(newd.x>=0 && newd.x<n && newd.y>=0 && newd.y<m && map[newd.x][newd.y]!=-1 && vis[newd.x][newd.y]==0)
{
newd.cost+=map[newd.x][newd.y];
if(newd.cost<cost[newd.x][newd.y])
{
if(flag[newd.x][newd.y])count++;
vis[newd.x][newd.y]=1;
cost[newd.x][newd.y]=newd.cost;
Q.push(newd);
}
}
}
}
while (!Q.empty()){Q.pop();}
for ( i = 0; i < k ; i++)
{
dis[num][i]=cost[point[i].x][point[i].y];
}
dis[num][k]=go_out;
dis[k][num]=go_out+map[point[num].x][point[num].y];
}
int main()
{
int t,i,j,s,temp,ans,states;
scanf("%d",&t);
while (t--)
{
memset(flag,0,sizeof(flag));
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
scanf("%d",&map[i][j]);
scanf("%d",&k);
for(i=0;i<k;i++)
{
scanf("%d%d",&point[i].x,&point[i].y);
flag[point[i].x][point[i].y]=1;
}
if (k==0)
{
printf("0\n");
continue;
}
states= (1<<(k+1))-1;
for ( i = 0; i < k; i++)bfs_que(i);
for ( i = 0; i <= states; i++)
for ( j = 0; j <=k ; j++)
dp[i][j]=MAXN;
for ( i = 0; i < k; i++)
{
dp[1<<i][i]=dis[k][i];
}
for ( i = 0; i <= states; i++)
{
for ( j = 0; j <= k ; j++)
{
for ( s = 0; s <= k ; s++)
{
if(s!=j && (i & (1<<j)) && (i & (1<<s)) && (temp= (i- (1<<j)) , dp[temp][s]!=MAXN) && dp[i][j]> dp[temp][s]+dis[s][j])
{
dp[i][j]=dp[temp][s]+dis[s][j];
}
}
}
}
printf("%d\n",dp[states][k]);
}
return 0;
}
/* WA 版
//大二寒假集训 第一章DP G_Hunter
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<functional>
#define MAXN 9999999
using namespace std;
typedef struct MyStruct
{
int x,y;
}Treasure;
typedef struct MyStruct1
{
int x,y;
}POINT;
Treasure point[15];
int map[210][210];
int dis[15][15];
int n,m,k,to;
int dp[8500][15];
int vis[210][210];
int cost[210][210];
int add[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
bool flag[210][210];
void bfs_0(int num)
{
int i,j;
int go_out=MAXN;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
cost[i][j]=MAXN;
POINT temp,newd;
temp.x=point[num].x;
temp.y=point[num].y;
cost[temp.x][temp.y]=0;
vis[temp.x][temp.y]=1;
queue<POINT>Q;
Q.push(temp);
while (!Q.empty())
{
temp=Q.front();
Q.pop();
vis[temp.x][temp.y]=0;
for ( i = 0; i < 4; i++)
{
newd=temp;
newd.x+=add[i][0];
newd.y+=add[i][1];
if(newd.x<1 || newd.x>n || newd.y<1 || newd.y>n)
{
if(cost[temp.x][temp.y]<go_out)
{go_out=cost[temp.x][temp.y];}
}
else if(map[newd.x][newd.y]!=-1)
{
if(cost[temp.x][temp.y]+map[newd.x][newd.y]<cost[newd.x][newd.y])
{
cost[newd.x][newd.y]=cost[temp.x][temp.y]+map[newd.x][newd.y];
if(!vis[newd.x][newd.y])
{
Q.push(newd);
vis[newd.x][newd.y]=1;
}
}
}
}
}
dis[0][num]=go_out+map[point[num].x][point[num].y];
dis[num][to]=go_out;
}
int main()
{
int t,i,j,s,temp,ans;
scanf("%d",&t);
while (t--)
{
memset(flag,0,sizeof(flag));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&map[i][j]);
scanf("%d",&k);to=k+1;
for(i=1;i<=k;i++)
{
scanf("%d%d",&point[i].x,&point[i].y);
point[i].x++;
point[i].y++;
flag[point[i].x][point[i].y]=true;
}
if(k==0)
{
printf("0\n");
continue;
}
for ( i = 1; i <= k ; i++)
{
bfs_0(i);//计算i号宝藏距图边缘的距离
for ( j = 1; j <=k ; j++)
{
dis[i][j]=cost[point[j].x][point[j].y];
}
dis[i][i]=map[point[i].x][point[i].y];
}
for(i=1;i<=(1<<k)-1;i++)
{
for(j=1;j<=k;j++)
{
if(i==(1<<(j-1)))dp[i][j]=dis[0][j];
else dp[i][j]= MAXN;
}
}
for ( i = 1; i <= (1<<k)-1; i++)
{
for ( j = 1; j <=k ; j++)
{
for ( s = 1; s <=k ; s++)
{
temp=i-(1<<(j-1));
if (s!=j && (i&(1<<(j-1))) && (i&(1<<(s-1))) && dp[temp][s]!=MAXN)
{
if(dp[i][j]>dp[temp][s]+dis[s][j])
dp[i][j]=dp[temp][s]+dis[s][j];
}
}
}
}
ans=MAXN;
for ( i = 1; i <=k; i++)
{
if(ans>dp[(1<<k)-1][i]+dis[i][to])
ans=dp[(1<<k)-1][i]+dis[i][to];
}
printf("%d\n",ans);
}
return 0;
}
*/