蓝书3.1 最小生成树

T1 井 luogu 1550

题目大意:

n个点 需要给每个点供水 在给第i个点供水需要花费v i

连接i号点和j号点 P_ij  求给所有点供水的最小代价

思路:

建立一个新节点 对所有点连接v i 边权的长度

然后跑kruskal

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 96100
12 #define eps 1e-5
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m;
22 struct edge{int u,v,val;}e[MAXN];
23 bool cmp(edge a,edge b) {return a.val<b.val;}
24 int fa[310];
25 int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
26 int ok(int u,int v)
27 {
28     int fu=find(u),fv=find(v);
29     if(fu==fv) return 1;
30     fa[fv]=fu;return 0;
31 }
32 void kruskal()
33 {
34     int cnt=0,ans=0;
35     sort(e+1,e+m+1,cmp);
36     for(int i=1;i<=m;i++)
37         if(cnt==n) break;
38         else if(!ok(e[i].u,e[i].v)) {cnt++,ans+=e[i].val;}
39     printf("%d",ans);
40 }
41 int main()
42 {
43     n=read(),fa[n+1]=n+1;
44     for(int i=1;i<=n;i++) fa[i]=i,e[++m].val=read(),e[m].u=i,e[m].v=n+1;
45     for(int i=1;i<=n;i++)
46         for(int j=1;j<=n;j++) e[++m].val=read(),e[m].u=i,e[m].v=j;
47     kruskal();
48 }
View Code

 

T2 最小完全图 codevs 2796

题目大意:

给一个MST 求一个完全图 该完全图使该MST唯一的最小完全图

思路:

将边排序 则每次合并两个联通块的时候只需要连sz[a]*sz[b]-1条长度为该树边权值+1的边即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 610*(1<<12)
12 using namespace std;
13 inline int read()
14 {
15     int x=0,f=1;char ch=getchar();
16     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
17     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
18     return x*f;
19 }
20 struct edge{int u,v,val;}e[MAXN];
21 bool cmp(edge a,edge b) {return a.val<b.val;}
22 int n,fa,fb,T,f[MAXN],sz[MAXN];
23 ll ans;
24 int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
25 int main()
26 {
27     n=read();
28     for(int i=1;i<n;i++) e[i].u=read(),e[i].v=read(),e[i].val=read(),f[i]=i,sz[i]=1,ans+=e[i].val;
29     f[n]=n,sz[n]=1;
30     sort(e+1,e+n,cmp);
31     for(int i=1;i<n;i++)
32     {
33         fa=find(e[i].u),fb=find(e[i].v);
34         f[fa]=fb;
35         ans+=(ll)(sz[fa]*sz[fb]-1)*(e[i].val+1);
36         sz[fb]+=sz[fa];
37     }
38     printf("%lld\n",ans);
39 }
View Code

 

T3 次小生成树  bzoj 1977

题目大意:

求严格次小生成树

思路:

每次枚举一个非树边  将这条边连接的两个点在树上路径上权值最大的边替换为这个边

因为是严格次小 所以如果这条边与权值最大的边边权相等 需要使用次大值

则该情况下生成树权值为原最小生成树权值-树边+非树边

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 100100
12 #define eps 1e-5
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m;
22 struct edge{int u,v,val,flag;}e[MAXN<<2];
23 bool cmp(edge a,edge b) {return a.val<b.val;}
24 int to[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1],fst[MAXN],cnt,fa[MAXN];
25 inline void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
26 inline int find(int x) {return x==fa[x]?fa[x]:fa[x]=find(fa[x]);}
27 int f[MAXN][20],mx[MAXN][20],dep[MAXN],submx[MAXN][20],in[MAXN<<2];
28 ll ans,Ans=214748364700000000LL;
29 void kruskal()
30 {
31     for(int i=1;i<=m;i++)
32     {
33         int u=e[i].u,v=e[i].v;
34         int f1=find(u),f2=find(v);
35         if(f1!=f2) {fa[f1]=f2,in[i]=1,ans+=e[i].val;add(u,v,e[i].val);add(v,u,e[i].val);}
36     }
37 }
38 inline void dfs(int x,int p)
39 {
40     for(int i=1;i<=18;i++)
41     {
42         if((1<<i)>=dep[x]) break;
43         f[x][i]=f[f[x][i-1]][i-1];
44         mx[x][i]=max(mx[x][i-1],mx[f[x][i-1]][i-1]);
45         if(mx[x][i-1]==mx[f[x][i-1]][i-1]) submx[x][i]=max(submx[x][i-1],submx[f[x][i-1]][i-1]);
46         else submx[x][i]=max(max(submx[x][i-1],submx[f[x][i-1]][i-1]),min(mx[x][i-1],mx[f[x][i-1]][i-1]));
47     }
48     for(int i=fst[x];i;i=nxt[i])
49         if(to[i]!=p) {dep[to[i]]=dep[x]+1,f[to[i]][0]=x;mx[to[i]][0]=val[i];dfs(to[i],x);}
50 }
51 inline void solve(ll u,ll v,ll w)
52 {
53     int res=0;
54     if(dep[u]<dep[v]) swap(u,v);
55     int t=dep[u]-dep[v];
56     for(int i=18;i>=0;i--) 
57         if(t&(1<<i))
58         {
59             if(mx[u][i]!=w) res=max(res,mx[u][i]);
60             else res=max(res,submx[u][i]);
61             u=f[u][i];
62         }
63     for(int i=18;i>=0;i--)
64         if(f[u][i]!=f[v][i])
65         {
66             if(mx[u][i]!=w) res=max(res,mx[u][i]);
67             else res=max(res,submx[u][i]);
68             if(mx[v][i]!=w) res=max(res,mx[v][i]);
69             else res=max(res,submx[v][i]);
70             u=f[u][i],v=f[v][i];
71         }
72     if(u!=v)
73     {
74         if(mx[u][0]!=w) res=max(res,mx[u][0]);
75         else res=max(res,submx[u][0]);
76         if(mx[v][0]!=w) res=max(res,mx[v][0]);
77         else res=max(res,submx[v][0]);
78     }
79     if(res) Ans=min(Ans,w-res);
80 }
81 int main()
82 {
83     n=read(),m=read();
84     for(int i=1;i<=n;i++) fa[i]=i;
85     for(int i=1;i<=m;i++) e[i].u=read(),e[i].v=read(),e[i].val=read();
86     sort(e+1,e+m+1,cmp);
87     kruskal();dfs(1,0);
88     for(int i=1;i<=m;i++) if(!in[i]) solve(e[i].u,e[i].v,e[i].val);
89     printf("%lld\n",ans+Ans);
90 }
View Code

 

T4 tree bzoj 2654

题解链接

 

T5 最小生成树计数 bzoj 1016

题解链接

posted @ 2018-07-23 10:21  jack_yyc  阅读(215)  评论(0编辑  收藏  举报