CHEAP DELIVERIES 给定k个路径求连续走完的最短路径(k<=18,)
题:https://ac.nowcoder.com/acm/contest/7818/B
题意:给定k个路径(s->t),在无向图上跑最短路径长度是多少?(n,m<=1e4,k<=18)
分析:
- 在走完某个路径后到达路径的t,要重新选择一条路径的起点来保证答案最优,这个过程就相当于dp的过程;
- k很小,我们可以对k进行状压,当第k-1位为1时,表示第k条路径已经走完,当然,当前状态是由哪条路径走来的也需要记录,所以开多一维dp记录状态的来源;
- 转移过程就是把状态为1的转移给自身状态为0的;
- 最短路就处理一下2*k个点开始的最短路;
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r typedef long long ll; const int mod=1e9+7; const int M=1e6+6; const int inf=0x3f3f3f3f; const ll INF=1e18; struct qnode{ int v; ll c; qnode(int _v=0,ll _c=0):v(_v),c(_c){} bool operator <(const qnode &r)const{ return c>r.c; } }; struct Edge{ int v; ll cost; Edge(int _v=0,ll _cost=0):v(_v),cost(_cost){} }; vector<Edge>E[M]; bool vis[M]; ll dist[M]; void Dij(int n,int start){ memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) dist[i]=INF; priority_queue<qnode>que; while(!que.empty())que.pop(); dist[start]=0; que.push(qnode(start,0)); qnode tmp; while(!que.empty()){ tmp=que.top(); que.pop(); int u=tmp.v; if(vis[u])continue; vis[u]=true; for(int i=0;i<E[u].size();i++){ int v=E[tmp.v][i].v; int cost=E[u][i].cost; if(!vis[v]&&dist[v]>dist[u]+cost){ dist[v]=dist[u]+cost; que.push(qnode(v,dist[v])); } } } } void addedge(int u,int v,ll w){ E[u].push_back(Edge(v,w)); } const int N=1e4+4; ll dis[40][N],dp[M][20]; int getid[N],tmp[N]; struct PP{ int x,y; }a[M]; int main(){ int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++){ int u,v; ll w; scanf("%d%d%lld",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } int tot=0; for(int i=1;i<=k;i++) scanf("%d%d",&a[i].x,&a[i].y),tmp[++tot]=a[i].x,tmp[++tot]=a[i].y; tot=unique(tmp+1,tmp+1+tot)-tmp-1; for(int i=1;i<=tot;i++){ getid[tmp[i]]=i; Dij(n,tmp[i]); for(int j=1;j<=n;j++) dis[i][j]=dist[j]; } memset(dp,0x3f,sizeof(dp)); for(int i=0;i<k;i++) dp[1<<i][i]=dis[getid[a[i+1].x]][a[i+1].y]; ll ans=INF; for(int i=1;i<(1<<k);i++) for(int j=0;j<k;j++) if(((1<<j)&i)==0){ for(int l=0;l<k;l++){ if(((1<<l)&i)) dp[i|(1<<j)][j]=min(dp[i|(1<<j)][j], dp[i][l] + dis[getid[a[l+1].y]][a[j+1].x] + dis[getid[a[j+1].x]][a[j+1].y]); } } for(int i=0;i<k;i++) ans=min(ans,dp[(1<<k)-1][i]); if(ans==INF) puts("-1"); else printf("%lld\n",ans); return 0; }