【bzoj5180】[Baltic2016]Cities 斯坦纳树

这题一看显然是一个裸的斯坦纳树

我们用$f[i][j]$表示经过的路径中包含了状态$i$所表示的点,且连接了$j$号点的最短路径。

显然,$f[i][j]=min\{f[i$^$k][j]+f[k][j]\}$, 其中$i $&$ k = k$。

转移完毕后,跑一个最短路去更新一遍。

那么显然这题的时间复杂度是$O(2^k\times 最短路时间复杂度)$。

但是这题神TM卡SPFA。。。。

我后来改写了$dij$,再加了个避免重复更新的判断,才过了...

 1 #include<bits/stdc++.h>
 2 #define M 100005
 3 #define L long long
 4 #define INF 1926081719260817LL
 5 using namespace std;
 6 struct edge{int u,v,next;}e[M<<2]={0}; int head[M]={0},use=0; 
 7 void add(int x,int y,int z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
 8 L f[1<<5][M]={0}; 
 9 struct node{
10     int u; L dis; node(){u=dis=0;}
11     node(int uu,L diss){u=uu; dis=diss;}
12     friend bool operator <(node a,node b){return a.dis>b.dis;}
13 }; priority_queue<node> q; 
14 bool vis[M]={0};
15 void spfa(L dfn[]){
16     memset(vis,0,sizeof(vis));
17     while(!q.empty()){
18         node uu=q.top(); q.pop(); 
19         int u=uu.u;
20         if(vis[u]) continue; vis[u]=1;
21         for(int i=head[u];i;i=e[i].next)
22         if(dfn[e[i].u]>dfn[u]+e[i].v){
23             dfn[e[i].u]=dfn[u]+e[i].v;
24             q.push(node(e[i].u,dfn[e[i].u]));
25         }
26     }
27 }
28 int n,m,k,p[10]={0};
29 
30 int main(){
31     scanf("%d%d%d",&n,&k,&m);
32     for(int i=0;i<(1<<k);i++)
33     for(int j=1;j<=n;j++) f[i][j]=INF;
34     for(int i=0;i<k;i++){
35         scanf("%d",p+i);
36         f[1<<i][p[i]]=0; 
37     }
38     for(int i=1;i<=m;i++){
39         int x,y,z; scanf("%d%d%d",&x,&y,&z);
40         add(x,y,z); add(y,x,z);
41     }
42     for(int i=1;i<(1<<k);i++){
43         for(int j=i;j;j=i&(j-1)){
44             for(int k=1;k<=n;k++)
45             f[i][k]=min(f[i][k],f[j][k]+f[i^j][k]);
46         }
47         for(int k=1;k<=n;k++)
48         if(f[i][k]!=INF) q.push(node(k,f[i][k]));
49         spfa(f[i]);
50     }
51     L minn=INF;
52     for(int i=1;i<=n;i++) 
53     minn=min(minn,f[(1<<k)-1][i]);
54     cout<<minn<<endl;
55 }

 

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/9249429.html