1. 程式人生 > >[POI 2007] 旅遊景點

[POI 2007] 旅遊景點

ret \n sca 最短 print false 題目 www. 城市

[題目鏈接]

https://www.lydsy.com/JudgeOnline/problem.php?id=1097

[算法]

首先,用Dijkstra算法求出2-k+1到每個點的最短路

然後,我們用f[S][i]表示目前停留城市集合為S,現在在城市i,最短的路徑

狀壓DP即可

[代碼]

#include<bits/stdc++.h>
using namespace std;
#define MAXN 20010
#define MAXM 200010
#define MAXK 25
const int INF = 2e9;
const int MAXS = 1 << 20; int i,j,x,n,m,k,u,v,w,tot,g,ts,ans,Mask; int head[MAXN],s[MAXK]; int dist[MAXK][MAXN],f[MAXS][MAXK]; bool visited[MAXN]; struct Edge { int to,w,nxt; } e[MAXM << 1]; inline void addedge(int u,int v,int w) { tot++; e[tot] = (Edge){v,w,head[u]}; head[u]
= tot; } inline void dijkstra(int s) { int i,v,w; priority_queue< pair<int,int> > q; pair<int,int> cur; for (i = 1; i <= n; i++) { dist[s][i] = INF; visited[i] = false; } dist[s][s] = 0; q.push(make_pair(0,s)); while (!q.empty()) { cur
= q.top(); q.pop(); if (visited[cur.second]) continue; visited[cur.second] = true; for (i = head[cur.second]; i; i = e[i].nxt) { v = e[i].to; w = e[i].w; if (dist[s][cur.second] + w < dist[s][v]) { dist[s][v] = dist[s][cur.second] + w; q.push(make_pair(-dist[s][v],v)); } } } } int main() { scanf("%d%d%d",&n,&m,&k); for (i = 1; i <= m; i++) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } scanf("%d",&g); for (i = 1; i <= g; i++) { scanf("%d%d",&u,&v); s[v] |= (1 << (u - 2)); } for (i = 1; i <= k + 1; i++) dijkstra(i); Mask = (1 << k) - 1; for (i = 0; i <= Mask; i++) { for (j = 1; j <= k + 1; j++) { f[i][j] = INF; } } for (i = 2; i <= k + 1; i++) { if (!s[i]) f[1 << (i - 2)][i] = dist[i][1]; } f[0][1] = 0; for (i = 0; i <= Mask; i++) { for (j = 1; j <= k + 1; j++) { for (x = 2; x <= k + 1; x++) { ts = i | (1 << (x - 2)); if (((s[x] & i) == s[x]) && f[i][j] + dist[j][x] < f[ts][x]) f[ts][x] = f[i][j] + dist[j][x]; } } } ans = INF; for (i = 1; i <= k + 1; i++) ans = min(ans,f[Mask][i] + dist[i][n]); printf("%d\n",ans); return 0; }

[POI 2007] 旅遊景點