HDU 4568 SPFA + TSP

这道题是长沙邀请赛的题,当时是道签到题。

这种题还是很常见的,讲一下思路。

首先是预处理出每个宝藏之间的距离,还有到边的距离,直接对每个宝藏进行一次SPFA就可以了。

然后就是经典的求TSP的过程。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 1111111111
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define infA(a) for (int i = 0 ; i <= n ; ++ i)a[i] = inf ;
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )


using namespace std;

inline void RD(int &ret) {
    char c;
    do {
        c = getchar();
    } while(c < '0' || c > '9') ;
    ret = c - '0';
    while((c=getchar()) >= '0' && c <= '9')
        ret = ret * 10 + ( c - '0' );
}

inline void OT(int a) {
    if(a >= 10)OT(a / 10) ;
    putchar(a % 10 + '0') ;
}
#define N 222
#define K 15


int Map[N][N] ;
struct tru {
    int x ,y ;
} tk[K] ;
int tt ;
int MM[K][K] ;
int dp[1 << K][K] ;
int dis[N][N] ;
bool vis[N][N] ;
PII qe[1111111] ;
int D[K] ;
int n , m ;
int mx[4] = {0 , 0 , 1 , -1} ;
int my[4] = {1 , -1 , 0 , 0} ;
int inmap(int x ,int y) {
    if(x >= 0 && x < n && y >= 0 && y < m && Map[x][y] != -1)return 1 ;
    return 0 ;
}
void init(int pos) {
    for (int i = 0 ; i < n ; i ++ ) {
        for (int j = 0 ; j < m ; j ++ ) {
            dis[i][j] = inf ;
            vis[i][j] = 0 ;
        }
    }
    dis[tk[pos].x][tk[pos].y] = Map[tk[pos].x][tk[pos].y] == -1 ? inf : 0 ;
    int h = 0 , t = 0 ;
    qe[h ++ ] = mp(tk[pos].x ,tk[pos].y) ;
    while(h > t) {
        PII tp = qe[t ++ ] ;
        vis[tp.FI][tp.SE] = 0 ;
        if(tp.FI == 0 || tp.FI == n - 1 || tp.SE == 0 || tp.SE == m - 1) {
            D[pos] = min(D[pos] , dis[tp.FI][tp.SE]) ;
        }
        for (int i = 0 ; i < 4 ; i ++ ) {
            int tx = tp.FI + mx[i] ;
            int ty = tp.SE + my[i] ;
            if(inmap(tx , ty)) {
                if(dis[tx][ty] > dis[tp.FI][tp.SE] + Map[tx][ty]) {
                    dis[tx][ty] = dis[tp.FI][tp.SE] + Map[tx][ty] ;
                    if(!vis[tx][ty]) {
                        vis[tx][ty] = 1 ;
                        qe[h ++ ] = mp(tx ,ty) ;
                    }
                }
            }
        }
    }
}


int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin) ;
    freopen("out.txt","w",stdout) ;
#endif
    int T ;
    cin >> T ;
    while ( T -- ) {
        cin >> n >> m ;
        REP(i , 0, n - 1 ) {
            REP(j , 0 , m - 1)scanf("%d",&Map[i][j]) ;
        }
        cin >> tt ;
        REP(i , 0 , tt - 1) {
            RD(tk[i].x) ;
            RD(tk[i].y) ;
        }
        REP(i , 0 , tt - 1) {
            REP(j , 0 , tt - 1) {
                MM[i][j] = inf ;
            }
            MM[i][i] = 0 ;
            D[i] = inf ;
        }
        for (int i = 0 ; i < (1 << tt) ; i ++ ) {
            for (int j = 0 ; j < tt ; j ++ )dp[i][j] = inf ;
        }

        REP(i , 0 , tt - 1) {
            init(i) ;
            REP(j , 0 , tt - 1) {
                if(i == j)continue ;
                MM[i][j] = min(MM[i][j] , dis[tk[j].x][tk[j].y]) ;//宝藏到宝藏之间的最近距离
            }
            dp[1 << i][i] = D[i] + Map[tk[i].x][tk[i].y] ;//该宝藏到达边的最近距离
        }
        for (int i = 0 ; i < 1 << tt ; i ++ ) {
            for (int j = 0 ; j < tt ; j ++ ) {
                if(i & (1 << j) == 0)continue ;
                if(dp[i][j] == inf)continue ;
                for (int k = 0 ; k < tt ; k ++ ) {
                    if(i & (1 << k))continue ;
                    int tp = i | (1 << k) ;
                    dp[tp][k] = min(dp[tp][k] , dp[i][j] + MM[j][k]) ;
                }
            }
        }
        int ans = inf ;
        for (int i = 0 ; i < tt ; i ++ ) {
            ans = min(ans , dp[(1 << tt) - 1][i] + D[i] ) ;
        }
        cout << ans << endl;
    }
    return 0 ;
}
/*
5
4 4
3 3 3 3
3 -1 -1 -1
3 -1 3 3
3 -1 -1 -1
1
2 2

5 5
1 1 1 1 1
1 -1 -1 -1 -1
1 -1 -1 -1 -1
1 -1 -1 -1 -1
1 -1 -1 -1 -1
2
4 0
0 4

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

*/


原文地址:https://www.cnblogs.com/javawebsoa/p/3249314.html