Description
Input
Output
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
这题太麻烦了==尤其是tsp没好好学的情况下 其中dp[i][j]: 从j出发,经过状态 i 上所有点的最短距离
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define MAX 205 #define inf 99999999 int n,m; struct pos{int x,y;}tr_pos[MAX]; int map[MAX * MAX],tr,val[14],dis[MAX * MAX]; int dir[4][2]={0,1,0,-1,-1,0,1,0}; int g[20][20],dp[1<<14][14]; int get_id(int x,int y){ if(x>=0 && x<n && y>=0 && y<m)return x*m+y; return n*m; } void spfa(int x){ for (int i = 0; i <= n*m; i++) dis[i] = inf;//dis数组是对应当前财宝所在位置距外部的最短距离,需要每次都初始化 dis[x] = (map[x]==-1?inf:map[x]); bool inq[205*205]; memset(inq,0,sizeof(inq)); queue<int>Q; while(!Q.empty())Q.pop(); Q.push(x); inq[x] = 1; int now; while(!Q.empty()){ now = Q.front(); Q.pop(); inq[now] = 0; if(now == n*m)continue; int r = now/m; int c = now%m; int nr,nc,nid; for (int i = 0; i < 4; i++) { nr = r + dir[i][0]; nc = c + dir[i][1]; nid = get_id(nr,nc); if(map[nid] == -1)continue; //更新 财宝点到边界的最短距离。 if(dis[nid] > dis[now] + map[nid]){ dis[nid] = dis[now] + map[nid]; if(!inq[nid]) Q.push(nid); inq[nid] = 1; } } } } int done(){ for (int i = 0; i < tr; i++) { spfa(get_id(tr_pos[i].x,tr_pos[i].y)); for (int j = 0; j < tr; j++) { int jid = get_id(tr_pos[j].x,tr_pos[j].y); g[i][j] = dis[jid]; if(g[i][j] == inf) return 0; } g[i][tr] = dis[n*m];//将n*m点看做一个花费为0的财宝点。 } return 1; } int solve() { if(tr == 0) return 0; int full = 1<<tr; for(int i = 0;i<full;i++) for(int j=0;j<tr;j++) dp[i][j] = inf; for (int i = 0; i < tr; i++) dp[1<<i][i] = g[i][tr]; for(int i = 1; i < full; ++i){ //当前状态为 i 状态(用二进制表示经过了哪些财宝点) for(int j = 0; j < tr; ++j){ if(i & (1<<j)){ //保证第j个财宝点在 i 状态中。 for(int k = 0; k < tr; ++k){ if( i & (1<<k) && j != k){ //第k个也要在,而且i!= j if(dp[i^(1<<k)][j] != inf) dp[i][k] = min(dp[i][k], dp[i^(1<<k) ][j] + g[j][k] - val[j]); } } } } } int res = inf; for (int i = 0; i < tr; i++) { res = min(res,dp[full-1][i] + g[i][tr]-val[i]); //full-1表示所有财宝点都包含的状态,g[][]表示两财宝点之间的最短距离,因为i的val记了两遍,故减去 } return res; } int main() { int cas,i,j; scanf("%d",&cas); while(cas--){ scanf("%d%d",&n,&m); for(i = 0;i < n;i++) for(j = 0;j < m;j++) scanf("%d",&map[i*m+j]); scanf("%d",&tr); for(i = 0;i < tr;i++){ scanf("%d%d",&tr_pos[i].x,&tr_pos[i].y); int id = get_id(tr_pos[i].x,tr_pos[i].y); val[i] = map[id]; } map[n*m] = 0;//从外部任意位置进入。 if(done())printf("%d\n",solve()); else printf("-1\n"); } return 0; }