1. 程式人生 > >解題:POI 2007 Tourist Attractions

解題:POI 2007 Tourist Attractions

題面

事實上這份程式碼在洛谷過不去,因為好像要用到一些壓縮空間的技巧,我並不想(hui)寫(捂臉)

先預處理$1$到$k+1$這些點之間相互的最短路和它們到終點的最短路,並記錄下每個點能夠轉移到時的狀態,然後就是狀壓dp辣。

設$dp[s][i]$表示狀態為$s$時處在點$i$的最短路,就可以$O(2^kk^2)$轉移了,注意最好減一些不合法狀態,因為這時間挺危險的=。=

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5
using namespace std; 6 const int N=20005,M=200005,K=22,inf=0x3f3f3f3f; 7 struct a{int node,dist;}; 8 bool operator < (a x,a y) 9 { 10 return x.dist>y.dist; 11 } 12 priority_queue<a> hp; 13 int dis[N],vis[N],ss[K],dp[(1<<20)+1][K]; 14 int p[N],noww[2*M],goal[2*M],val[2*M],mat[K][K];
15 int n,m,k,c,t1,t2,t3,cnt,len,all,ans=inf; 16 void link(int f,int t,int v) 17 { 18 noww[++cnt]=p[f],p[f]=cnt; 19 goal[cnt]=t,val[cnt]=v; 20 } 21 void Dijkstra(int s) 22 { 23 memset(vis,0,sizeof vis); 24 memset(dis,0x3f,sizeof dis); 25 dis[s]=0,hp.push((a){s,0}); 26 while(!hp.empty())
27 { 28 a tt=hp.top(); hp.pop(); int tn=tt.node; 29 if(vis[tn]) continue ; vis[tn]=true; 30 for(int i=p[tn];i;i=noww[i]) 31 if(dis[goal[i]]>dis[tn]+val[i]) 32 dis[goal[i]]=dis[tn]+val[i],hp.push((a){goal[i],dis[goal[i]]}); 33 } 34 } 35 int ins(int x) 36 { 37 return 1<<(x-2); 38 } 39 int main () 40 { 41 scanf("%d%d%d",&n,&m,&k),all=(1<<k)-1; 42 for(int i=1;i<=m;i++) 43 { 44 scanf("%d%d%d",&t1,&t2,&t3); 45 link(t1,t2,t3),link(t2,t1,t3); 46 } 47 scanf("%d",&c); 48 for(int i=1;i<=c;i++) 49 scanf("%d%d",&t1,&t2),ss[t2]|=ins(t1); 50 for(int i=1;i<=k+1;i++) 51 { 52 Dijkstra(i); 53 for(int j=1;j<=k+1;j++) 54 mat[i][j]=dis[j]; mat[i][0]=dis[n]; 55 } 56 memset(dp,0x3f,sizeof dp),dp[0][1]=0; 57 for(int i=0;i<=all;i++) 58 for(int j=1;j<=k+1;j++) 59 if(dp[i][j]!=inf) 60 for(int h=2;h<=k+1;h++) 61 if((i&ss[h])==ss[h]) 62 dp[i|ins(h)][h]=min(dp[i|ins(h)][h],dp[i][j]+mat[j][h]); 63 for(int i=1;i<=k+1;i++) ans=min(ans,dp[all][i]+mat[i][0]); 64 printf("%d",ans); 65 return 0; 66 }
View Code