BZOJ2561 最小生成树
这题乍一看很没有办法下手、、、
但是我们可以想到说、如果一个边有放在MST上的可能、那么权值小于它的边肯定做不出一个生成树、
(这里貌似有个定理,就是说对同一个无向图的所有最小生成树对应权的边的数量对应相等,比如都有2条权为1的和一条权为2的,所以可以得到上面这个结论)
那么肯定是要在权值小于它的边中删掉一些使得剩下的不能做成一个生成树、没错就是最小割、、
可以这样想、
对于一条边,要是MST中的一条边,必然存在一种情况下,它连接着相互之间最小边权不小于它的边权的两个连通块(……)、
而对于建成的新图,如果我们不把u和v割开,那么必然不会存在上述情况、、
所以两次建图求mincut(即maxflow)然后加起来就好了、
Code:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int INF=9999999; const int maxn=20001; const int maxm=400001; int g[maxn],e[maxn],h[maxn],vd[maxn]; int a[maxm],b[maxm],w[maxm],f[maxm],next[maxm],t[maxm],ret[maxm]; int n,m,r,u,v,l,ans=0; void setup(){ memset(g,0,sizeof g); memset(e,0,sizeof e); memset(h,0,sizeof h); memset(vd,0,sizeof vd); memset(f,0,sizeof f); memset(next,0,sizeof next); memset(t,0,sizeof t); r=0;vd[0]=n; } int sap(int x,int flow){ //cout <<x <<endl; int pu=g[x],p=0,q; if (v==x) return flow; while (pu){ if (h[x]==h[t[pu]]+1 && f[pu]){ q=sap(t[pu],min(flow-p,f[pu])); p+=q;f[pu]-=q;f[ret[pu]]+=q; if (p==flow) return flow; } pu=next[pu]; } vd[h[x]]--; if (!vd[h[x]]) h[u]=n; h[x]++;vd[h[x]]++; return p; } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) scanf("%d%d%d",&a[i],&b[i],&w[i]); scanf("%d%d%d",&u,&v,&l); setup(); for (int i=1;i<=m;i++) if (w[i]<l){ t[++r]=b[i];f[r]=1; if (!g[a[i]]) g[a[i]]=e[a[i]]=r; else {next[e[a[i]]]=r;e[a[i]]=r;} t[++r]=a[i];f[r]=1; if (!g[b[i]]) g[b[i]]=e[b[i]]=r; else {next[e[b[i]]]=r;e[b[i]]=r;} ret[r]=r-1;ret[r-1]=r; } while (h[u]<n) ans+=sap(u,INF); setup(); for (int i=1;i<=m;i++) if (w[i]>l){ t[++r]=b[i];f[r]=1; if (!g[a[i]]) g[a[i]]=e[a[i]]=r; else {next[e[a[i]]]=r;e[a[i]]=r;} t[++r]=a[i];f[r]=1; if (!g[b[i]]) g[b[i]]=e[b[i]]=r; else {next[e[b[i]]]=r;e[b[i]]=r;} ret[r]=r-1;ret[r-1]=r; } while (h[u]<n) ans+=sap(u,INF); cout <<ans <<endl; while(1); return 0; }