[BZOJ1937][SHOI2004]Mst 最小生成樹
阿新 • • 發佈:2018-08-05
desc https const () space ret using max lse 的邊權,也就是\(w_j+d_j \ge w_i-d_i\),移項後\(d_i+d_j \ge w_i-w_j\)。
這個東西就是\(KM\)頂表的要求。所以直接跑\(KM\)就可以了。復雜度可以做到\(O(nm^2)\)
bzoj
luogu
description
給一張\(n\)點\(m\)條邊的帶權圖,保證無重邊無自環,並給出這張圖的一棵生成樹。你可以任意修改每條邊的邊權,但是要求修改後邊權仍是整數。修改的代價定義為邊權的變化量。你需要保證邊權修改後給出的生成樹是原圖的最小生成樹(可以不唯一)。
求最小修改代價。
\(n\le50,m\le800\)。
sol
其實做這道題的原因是今天打百度之星的時候發現自己並不會KM
首先很顯然,樹邊的邊權只可能減小,非樹邊的邊權只可能增大。
設每條邊的修改量為\(d_i\),我們考慮每一條非樹邊\(i\),對於它覆蓋到的每一條樹邊\(j\),我們要求修改後\(i\)的邊權不小於\(j\)
這個東西就是\(KM\)頂表的要求。所以直接跑\(KM\)就可以了。復雜度可以做到\(O(nm^2)\)
code
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 1005; const int inf = 1<<30; struct edge{int u,v,w;}E[N]; int n,m,to[N],nxt[N],ww[N],head[N],cnt=1,fa[N],dep[N],ref[N],a[N][N],tot; int slack[N],lv[N],rv[N],mat[N],vis[N],pre[N]; void link(int u,int v,int w){ to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt; } void dfs(int u,int f){ fa[u]=f;dep[u]=dep[f]+1; for (int e=head[u];e;e=nxt[e]) if (to[e]!=f) ref[to[e]]=e>>1,dfs(to[e],u); } void aug(int s){ for (int i=0;i<=tot;++i) slack[i]=inf,vis[i]=pre[i]=0; int u=0;mat[u]=s; do{ int now=mat[u],d=inf,nxt;vis[u]=1; for (int v=1;v<=tot;++v) if (!vis[v]){ if (lv[now]+rv[v]-a[now][v]<slack[v]) slack[v]=lv[now]+rv[v]-a[now][v],pre[v]=u; if (d>slack[v]) d=slack[v],nxt=v; } for (int i=0;i<=tot;++i) if (vis[i]) lv[mat[i]]-=d,rv[i]+=d; else slack[i]-=d; u=nxt; }while (mat[u]); while (u) mat[u]=mat[pre[u]],u=pre[u]; } int main(){ freopen("1937.in","r",stdin); freopen("1937.out","w",stdout); n=gi();m=gi();tot=max(n-1,m-n+1); for (int i=1;i<=m;++i){ E[i]=(edge){gi(),gi(),gi()}; if (E[i].u>E[i].v) swap(E[i].u,E[i].v); } for (int i=1;i<n;++i){ int u=gi(),v=gi(),w;if (u>v) swap(u,v); for (int j=1;j<=m;++j) if (E[j].u==u&&E[j].v==v){ w=E[j].w;vis[j]=1;break; } link(u,v,w);link(v,u,w); } dfs(1,0); for (int i=1,num=0;i<=m;++i) if (!vis[i]){ int u=E[i].u,v=E[i].v;++num; while (u^v){ if (dep[u]<dep[v]) swap(u,v); int e=ref[u];a[e][num]=ww[e<<1]-E[i].w; u=fa[u]; } } for (int i=1;i<=tot;++i) for (int j=1;j<=tot;++j) lv[i]=max(lv[i],a[i][j]); for (int i=1;i<n;++i) aug(i); int ans=0; for (int i=1;i<=tot;++i) ans+=lv[i]+rv[i]; printf("%d\n",ans); return 0; }
[BZOJ1937][SHOI2004]Mst 最小生成樹