# BZOJ1097: [POI2007]旅游景点atr

$n \leq 20000,m \leq 200000$的无向边权图无自环重边，问：从1出发到$n$，必须经过$2,3,...,k+1$，$k \leq 20$，且满足$q$个限制：在访问$x$后一定要访问$y$，$x,y<=k+1$，这样的最短路。

 1 #include<stdio.h>
2 #include<string.h>
3 #include<queue>
4 #include<stdlib.h>
5 #include<algorithm>
6 //#include<iostream>
7 using namespace std;
8
9 #define LL long long
11 {
12     char c; int s=0,t=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (t=-1);
13     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*t;
14 }
15
16 //Pay attention to LL and double of qread!!!!
17
18 int n,m,K,lq;
19 #define maxn 20011
20 #define maxm 400011
21 #define maxs 1111111
22 struct Edge{int to,v,next;}edge[maxm]; int first[maxn],le=2;
23 void in(int x,int y,int v) {Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;}
24 void insert(int x,int y,int v) {in(x,y,v); in(y,x,v);}
25
26 struct qnode
27 {
28     int v,id;
29     bool operator < (const qnode &b) const {return v>b.v;}
30 };
31 priority_queue<qnode> q;
32 int ddd[maxn],dis[25][25];
33 void dijkstra(int s)
34 {
35     for (int i=1;i<=n;i++) ddd[i]=0x3f3f3f3f;
36     ddd[s]=0; q.push((qnode){0,s});
37     while (!q.empty())
38     {
39         int x=q.top().id,d=q.top().v; q.pop();
40         if (ddd[x]!=d) continue;
41         for (int i=first[x];i;i=edge[i].next)
42         {
43             Edge &e=edge[i];
44             if (ddd[e.to]>ddd[x]+e.v)
45             {
46                 ddd[e.to]=ddd[x]+e.v;
47                 q.push((qnode){ddd[e.to],e.to});
48             }
49         }
50     }
51     for (int i=1;i<=K+1;i++) dis[s][i]=ddd[i];
52     dis[s][K+2]=ddd[n];
53 }
54
55 int lim[233],f[maxs][20];
56 int main()
57 {
59     for (int i=1,x,y,v;i<=m;i++)
60     {
62         insert(x,y,v);
63     }
65     for (int i=1,x,y;i<=lq;i++)
66     {
68         lim[y]|=1<<(x-2);
69     }
70 //    for (int i=2;i<=K+1;i++) cout<<lim[i]<<' ';cout<<endl;
71
72     for (int i=1;i<=K+1;i++) dijkstra(i);
73     if (K==0) {printf("%d\n",dis[1][2]); return 0;}
74
75     memset(f,0x3f,sizeof(f));
76     for (int i=0;i<K;i++) if (lim[i+2]==0) f[1<<i][i]=dis[1][i+2];
77     for (int i=1;i<(1<<K);i++)
78     {
79 //        for (int j=0;j<K;j++) cout<<((i>>j)&1)<<' '; for (int j=0;j<K;j++) cout<<f[i][j]<<' ';cout<<endl;
80         for (int j=0;j<K;j++) if (((i>>j)&1)==0 && (i&lim[j+2])==lim[j+2])
81         {
82             int ni=i|(1<<j);
83             for (int k=0;k<K;k++) f[ni][j]=min(f[ni][j],f[i][k]+dis[k+2][j+2]);
84         }
85     }
86     int ans=0x3f3f3f3f;
87     for (int i=0;i<K;i++) ans=min(ans,f[(1<<K)-1][i]+dis[i+2][K+2]);
88     printf("%d\n",ans);
89     return 0;
90 }
View Code

posted @ 2018-05-03 18:35  Blue233333  阅读(225)  评论(0编辑  收藏  举报