HDU-4568 TSP+最短路

题意:给一个n行m列的矩阵,矩阵上的数字代表经过代价(这里要注意每经过一次都要付出代价),矩阵上有几个宝藏,猎人可以从任意边界进去矩阵取完所有宝藏后从任意边界出来。

解法:一看到宝藏数量小于等于13且必须经过,应该很容易想到TSP问题。所以我们用最短路预处理+状态压缩DP解决。首先预处理所有宝藏点到整个地图的最短路这是为了后续的dp代价做准备,然后开始状压dp,设计dp状态为dp[S][now]代表现在去了的宝藏点集为S且现在在now宝藏点的最小值,用记忆化搜索转移即可。

细节详见代码,应该挺好懂的:

#include<bits/stdc++.h>
using namespace std;
const int N=210;
const int INF=0x3f3f3f3f;
const int dx[]={-1,0,1,0};
const int dy[]={0,1,0,-1};
int n,m,k,a[N][N],dp[1<<15][15],es[N],px[N],py[N];

struct dat{
    int d,x,y;
    bool operator < (const dat &rhs) const {
        return d>rhs.d;
    }
};
priority_queue<dat> q;
int dis[15][N][N];
bool vis[N][N];
void Dijkstra(int k) {
    memset(dis[k],0x3f,sizeof(dis[k]));
    memset(vis,0,sizeof(vis));
    q.push((dat){0,px[k],py[k]});
    dis[k][px[k]][py[k]]=0;
    while (!q.empty()) {
        dat u=q.top(); q.pop();
        if (vis[u.x][u.y]) continue;
        vis[u.x][u.y]=1;
        for (int i=0;i<4;i++) {
            int tx=u.x+dx[i],ty=u.y+dy[i];
            if (tx<1 || tx>n || ty<1 || ty>m || a[tx][ty]==-1) continue;
            if (dis[k][tx][ty]>dis[k][u.x][u.y]+a[tx][ty]) {
                dis[k][tx][ty]=dis[k][u.x][u.y]+a[tx][ty];
                q.push((dat){dis[k][tx][ty],tx,ty});
            }
        }
    }
}

int lowbit(int x) { int ret=0; for (;x;x-=x&-x) ret++; return ret; }

int dfs(int now,int x) {
    if (dp[now][x]!=-1) return dp[now][x];
    if (lowbit(now)==1) return es[x]+a[px[x]][py[x]];
    dp[now][x]=INF;
    for (int i=1;i<=k;i++)
        if ((i!=x) && (now&(1<<i-1))) {
            int tmp=dfs(now^(1<<x-1),i)+dis[i][px[x]][py[x]];
            dp[now][x]=min(dp[now][x],tmp);
    }
    return dp[now][x];    
}

int main()
{
    int T; cin>>T;
    while (T--) {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
        scanf("%d",&k);
        for (int i=1;i<=k;i++) {
            scanf("%d%d",&px[i],&py[i]); 
            px[i]++; py[i]++;
            Dijkstra(i);
            es[i]=INF;
            for (int j=1;j<=n;j++) es[i]=min(es[i],min(dis[i][j][1],dis[i][j][m]));
            for (int j=1;j<=m;j++) es[i]=min(es[i],min(dis[i][1][j],dis[i][n][j]));
        }
        memset(dp,-1,sizeof(dp));
        int ans=INF;
        for (int i=1;i<=k;i++) ans=min(ans,dfs((1<<k)-1,i)+es[i]);
        if (ans==INF) printf("-1"); else printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/clno1/p/10934224.html