[题目链接]

       ​​ 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;
}