分析
很套路的一道题,但是初始值初始时有点搞心态。主要是考虑到 ,很自然的想到用状压去维护。定义 为当前节点在 ,已经过了的节点状态为 。那么我们的转移也比较简单 。那么我们只需要预处理 即可。
代码
#include<bits/stdc++.h> using namespace std; #define LL long long const LL N = 2e5 + 1000,M = 3e5 + 10,inf = 1e18; LL read() { LL x=0,f=0;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-')f=1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return f?-x:x; } #define pii pair<LL,LL> bool vis[N]; vector<pii> G[N]; struct Edge{LL to,nxt,w;}e[N]; struct Node{ LL pos,dis; bool operator <(const Node x) const { return dis > x.dis; } }; priority_queue<Node> Q; LL n,m,K,f[20][M],dis[20][20],A[N],B[N],dist[N]; void solve(LL S) { while(Q.size())Q.pop();Q.push((Node){S,dist[S]=0}); while(Q.size()){LL x=Q.top().pos;Q.pop();if(vis[x])continue; vis[x]=1;for(auto E:G[x]) { if(dist[E.first]>dist[x]+E.second) { dist[E.first]=dist[x]+E.second; Q.push((Node){E.first,dist[E.first]}); } } } } int main() { n=read();m=read();K = read(); for(LL i = 1,a,b,c;i <= m;i++) { a=read();b=read();c=read(); G[a].push_back(pii(b,c)); G[b].push_back(pii(a,c)); } for(LL i = 1;i <= K;i++) A[i]=read(),B[i]=read(); for(LL i = 1;i <= K;i++) { // memset(dist,0x3f,sizeof(dist));memset(vis,0,sizeof(vis)); for(int j=1;j<=n;j++)dist[j]=inf,vis[j]=0; solve(B[i]); for(LL j = 1;j <= K;j++) dis[i][j] = dist[A[j]]; } for(int i=1;i<(1<<K);i++) { for(int j=1;j<=K;j++)f[j][i]=inf; } for(LL i = 1;i <= K;i++) f[i][1<<i-1] = dis[i][i]; for(int s=1;s<(1<<K);s++){ for(int i=1;i<=K;i++)if(s&(1<<(i-1))){ for(int j=1;j<=K;j++){ if(s&(1<<(j-1))) continue; f[j][s|(1<<(j-1))]=min(f[j][s|(1<<(j-1))],f[i][s]+dis[i][j]+dis[j][j]); } } } LL ans = inf; for(LL i=1;i<=K;i++) ans=min(f[i][(1<<K)-1],ans); if(ans>=inf)cout<<"-1"<<endl; else cout<<ans<<endl;return 0; }