题意:遍历所有的城市的最短路径,每个城市最多去两遍。将城市的状态用3进制表示。
状态转移方程为 dp[NewS][i]=min( dp[NewS][i],dp[S][j]+dis[i][j])
S表示遍历点的状态,i表示到达第i个城市。
在到第i个城市的时候看是否存在一个j城市的路径,然后再从j到i更短。
#include <algorithm> #include <cstdio> #include <cstring> #define Max 1000001 #define MAXN 150000 #define MOD 100000000 #define rin freopen("in.txt","r",stdin) #define rout freopen("1.out","w",stdout) #define Del(a,b) memset(a,b,sizeof(a)) #define INF 0x1f1f1f1f using namespace std; typedef long long LL; int edge[11][11]; int n, m; int tri[] = { 0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049 }; int dp[59050][11]; int dig[59050][11]; void Init() { Del(dp, INF); Del(edge, INF); for (int i = 1; i <= n; i++) { dp[tri[i]][i] = 0; } } void Solve() { int ans = INF; for (int S = 0; S < tri[n+1]; S++) { int flag = 1; for (int i = 1; i <= n; i++) { if (dig[S][i] == 0) flag = 0; if (dp[S][i] == INF) continue; for (int j = 1; j <= n; j++) { if (i == j) continue; if (edge[i][j] == INF || dig[S][j] == 2) continue; int NewS = S + tri[j]; dp[NewS][j] = min(dp[NewS][j], dp[S][i] + edge[i][j]); } } if (flag) { for (int j = 1; j <= n; j++) ans = min(ans, dp[S][j]); } } if (ans == INF) { puts("-1"); } else { printf("%d\n", ans); } return; } int main() { //rin; for (int i = 0; i < 59050; i++) { int t = i; for (int j = 1; j <= 10; j++) { dig[i][j] = t % 3; t /= 3; if (t == 0) break; } } while (scanf("%d%d", &n, &m) != EOF) { Init(); for (int i = 0; i < m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); if (c < edge[a][b]) edge[a][b] = edge[b][a] = c; } Solve(); } return 0; }
时间: 2024-10-13 00:57:37