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 }
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 ",ans); 39 }
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 ",ans+Ans); 90 }
T4 tree bzoj 2654
T5 最小生成树计数 bzoj 1016