BZOJ 1097: [POI2007]旅游景点atr [DP 状压 最短路]
Posted Candy?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1097: [POI2007]旅游景点atr [DP 状压 最短路]相关的知识,希望对你有一定的参考价值。
题意:
一个无向图,从$1$到$n$,要求必须经过$2,3,...,k+1$,给出一些限制关系,要求在经过$v \le k+1$之前必须经过$u \le k+1$
求最短路
预处理出$1...k+1$到其他点的最短路
然后$f[i][s]$表示当前在$i$已经经过的点的集合为$s$的最短路
只考虑$1,2,...,k+1$就行了,
注意$1$也要考虑,一个点可能经过多次
然后实测dij比spfa快....我想试$pb\_ds$来着结果发现我的电脑上没有ext/pb_ds/priority_queue.hpp
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N=2e4+5,M=2e5+5,K=22,S=(1<<20)+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } int n,m,k,u,v,w; int need[K],f[K][S]; int d[K][N]; struct Edge{ int v,w,ne; }e[M<<1]; int cnt,h[N]; inline void ins(int u,int v,int w){ cnt++; e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt; } int q[N],head,tail,inq[N]; inline void lop(int &x){if(x==N) x=1;else if(x==0) x=N-1;} void spfa(int s,int *d){ head=tail=1; d[s]=0;inq[s]=1; q[tail++]=s; while(head!=tail){ int u=q[head++];inq[u]=0;lop(head); for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(d[v]>d[u]+e[i].w){ d[v]=d[u]+e[i].w; if(!inq[v]){ inq[v]=1; if(d[v]<d[q[head]]) head--,lop(head),q[head]=v; else q[tail++]=v,lop(tail); } } } } } int main(){ freopen("in","r",stdin); n=read();m=read();k=read(); for(int i=1;i<=m;i++) u=read(),v=read(),w=read(),ins(u,v,w); memset(d,127,sizeof(d)); for(int i=1;i<=k+1;i++) spfa(i,d[i]); int c=read(); while(c--) u=read()-2,v=read(),need[v]|=(1<<u); memset(f,-1,sizeof(f)); int All=1<<k; f[1][0]=0; for(int s=0;s<All;s++) for(int i=1;i<=k+1;i++) if(f[i][s]!=-1){ for(int j=2;j<=k+1;j++) if(j!=i && (need[j]&s)==need[j] ){ int t=s|(1<<(j-2)); if(f[j][t]>f[i][s]+d[i][j] || f[j][t]==-1) f[j][t]=f[i][s]+d[i][j]; } } int ans=INF; for(int i=1;i<=k+1;i++) if(f[i][All-1]!=-1) ans=min(ans,f[i][All-1]+d[i][n]); printf("%d",ans); }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define MP make_pair #define fir first #define sec second typedef long long ll; const int N=2e4+5,M=2e5+5,K=22,S=(1<<20)+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } int n,m,k,u,v,w; int need[K],f[K][S]; int d[K][N]; struct Edge{ int v,w,ne; }e[M<<1]; int cnt,h[N]; inline void ins(int u,int v,int w){ cnt++; e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt; } priority_queue<pii,vector<pii>,greater<pii> > q; bool done[N]; void dij(int s,int *d){ for(int i=1;i<=n;i++) d[i]=INF,done[i]=0; d[s]=0; q.push(MP(d[s],s)); while(!q.empty()){ int u=q.top().sec;q.pop(); if(done[u]) continue;done[u]=1; for(int i=h[u];i;i=e[i].ne) if(d[e[i].v]>d[u]+e[i].w){ d[e[i].v]=d[u]+e[i].w; q.push(MP(d[e[i].v],e[i].v)); } } } int main(){ freopen("in","r",stdin); n=read();m=read();k=read(); for(int i=1;i<=m;i++) u=read(),v=read(),w=read(),ins(u,v,w); memset(d,127,sizeof(d)); for(int i=1;i<=k+1;i++) dij(i,d[i]); int c=read(); while(c--) u=read()-2,v=read(),need[v]|=(1<<u); memset(f,-1,sizeof(f)); int All=1<<k; f[1][0]=0; for(int s=0;s<All;s++) for(int i=1;i<=k+1;i++) if(f[i][s]!=-1){ for(int j=2;j<=k+1;j++) if(j!=i && (need[j]&s)==need[j] ){ int t=s|(1<<(j-2)); if(f[j][t]>f[i][s]+d[i][j] || f[j][t]==-1) f[j][t]=f[i][s]+d[i][j]; } } int ans=INF; for(int i=1;i<=k+1;i++) if(f[i][All-1]!=-1) ans=min(ans,f[i][All-1]+d[i][n]); printf("%d",ans); }
以上是关于BZOJ 1097: [POI2007]旅游景点atr [DP 状压 最短路]的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1097[POI2007]旅游景点atr 最短路+状压DP
BZOJ_1097_[POI2007]旅游景点atr_状压DP