[cf1149D]Abandoning Roads

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

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

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

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

[cf1149D]Abandoning Roads
 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)ss|=bl[k];
37             if (((ss&bl[v])==0)&&(d[v][ss]>d[k][s]+edge[i].len)){
38                 d[v][ss]=d[k][s]+edge[i].len;
39                 if (!vis[v][ss]){
40                     vis[v][ss]=1;
41                     q.push(make_pair(v,ss));
42                 }
43             }
44         }
45         vis[k][s]=0;
46     }
47 }
48 int main(){
49     scanf("%d%d%d%d",&n,&m,&a,&b);
50     memset(head,-1,sizeof(head));
51     for(int i=1;i<=n;i++){
52         f[i]=i;
53         sz[i]=1;
54     }
55     for(int i=1;i<=m;i++){
56         scanf("%d%d%d",&x,&y,&z);
57         if (z==a)merge(x,y);
58         add(x,y,z);
59         add(y,x,z);
60     }
61     m=0;
62     for(int i=1;i<=n;i++)
63         if ((f[i]==i)&&(sz[i]>=4))bl[i]=(1<<m++);
64     for(int i=1;i<=n;i++)bl[i]=bl[find(i)];
65     spfa();
66     for(int i=1;i<=n;i++){
67         int ans=0x3f3f3f3f;
68         for(int j=0;j<(1<<m);j++)ans=min(ans,d[i][j]);
69         printf("%d ",ans);
70     }
71 }
View Code

 

上一篇:CF835F Roads in the Kingdom


下一篇:1087 All Roads Lead to Rome (30 分)