[cf1149D]Abandoning Roads

根据kruskal的贪心过程,先将所有$a$类边连起来,对于一个连通块内的两点,必然通过$a$边联通

考虑对于一条最短路径,必然是一段(可能为空)$a$类边+1条$b$类边,同时其合法当且仅当这些$b$类边都能被加入最小生成树中,即不会与$a$类边产生环,又即不重复经过一个连通块

状压之前经过的连通块求最短路(当使用$b$类边离开后再加入),那么时间复杂度为$o(2^{n}m)$

注意到我们是在求最短路径,若一个连通块点数小于4,则必然从连通块内部走,因此复杂度变为$o(2^{\frac{n}{4}}m)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 105
 4 struct ji{
 5     int nex,to,len;
 6 }edge[N<<2];
 7 queue<pair<int,int> >q;
 8 int E,n,m,a,b,x,y,z,head[N],f[N],sz[N],bl[N],vis[N][200005],d[N][200005];
 9 int find(int k){
10     if (k==f[k])return k;
11     return f[k]=find(f[k]);
12 }
13 void merge(int x,int y){
14     x=find(x),y=find(y);
15     if (x!=y){
16         f[x]=y;
17         sz[y]+=sz[x];
18     }
19 }
20 void add(int x,int y,int z){
21     edge[E].nex=head[x];
22     edge[E].to=y;
23     edge[E].len=z;
24     head[x]=E++;
25 }
26 void spfa(){
27     memset(d,0x3f,sizeof(d));
28     d[1][0]=0;
29     vis[1][0]=1;
30     q.push(make_pair(1,0));
31     while (!q.empty()){
32         int k=q.front().first,s=q.front().second;
33         q.pop();
34         for(int i=head[k];i!=-1;i=edge[i].nex){
35             int v=edge[i].to,ss=s;
36             if (edge[i].len==b){
37                 if (find(edge[i].to)==find(k))continue;
38                 ss|=bl[k];
39             }
40             if (((ss&bl[v])==0)&&(d[v][ss]>d[k][s]+edge[i].len)){
41                 d[v][ss]=d[k][s]+edge[i].len;
42                 if (!vis[v][ss]){
43                     vis[v][ss]=1;
44                     q.push(make_pair(v,ss));
45                 }
46             }
47         }
48         vis[k][s]=0;
49     }
50 }
51 int main(){
52     scanf("%d%d%d%d",&n,&m,&a,&b);
53     memset(head,-1,sizeof(head));
54     for(int i=1;i<=n;i++){
55         f[i]=i;
56         sz[i]=1;
57     }
58     for(int i=1;i<=m;i++){
59         scanf("%d%d%d",&x,&y,&z);
60         if (z==a)merge(x,y);
61         add(x,y,z);
62         add(y,x,z);
63     }
64     m=0;
65     for(int i=1;i<=n;i++)
66         if ((f[i]==i)&&(sz[i]>=4))bl[i]=(1<<m++);
67     for(int i=1;i<=n;i++)bl[i]=bl[find(i)];
68     spfa();
69     for(int i=1;i<=n;i++){
70         int ans=0x3f3f3f3f;
71         for(int j=0;j<(1<<m);j++)ans=min(ans,d[i][j]);
72         printf("%d ",ans);
73     }
74 }
View Code

 

posted @ 2021-05-27 14:55  PYWBKTDA  阅读(41)  评论(0编辑  收藏  举报