對於線性規劃對偶這一套不熟悉的同學可以看我的這篇博客最後你會發現我還是在讓你去看集訓隊論文
對於我們需要的最小生成樹,首先樹邊只會減小,非樹邊只會增加,考慮所有非樹邊,他的兩個端點在樹上的簡單路徑上的所有非樹邊,那麼的減量的增量。
所以可以列出線性規劃:
對偶即可得到:
上面的指的是一個點的出流量和(也是入流量和),也就是說這是一個限制了每個點可以匹配的邊數的最大權匹配,可以用費用流解決。
注意是最大費用流,無需最大流,在的中寫即可。
#include<bits/stdc++.h>
#define maxn 2005
#define inf 0x3f3f3f3f
#define maxm maxn * maxn
using namespace std;
int n,m;
int fir[maxn],nxt[maxn],tar[maxn],eid[maxn],wgt[maxn],cnte;
void add(int u,int v,int id,int w){ nxt[++cnte]=fir[u],fir[u]=cnte,tar[cnte]=v,eid[cnte]=id,wgt[cnte]=w; }
int buf[maxn],info[maxn],Prev[maxm],to[maxm],cst[maxm],cap[maxm],cnt_e=1;
void Node(int u,int v,int c,int ct){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cap[cnt_e]=c,cst[cnt_e]=ct; }
void Line(int u,int v,int c,int ct){ Node(u,v,c,ct),Node(v,u,0,-ct); }
int S,T,ans,h[maxn];
int ser(int u,int ff,int T,int id,int w){
if(u == T) return 1;
for(int i=fir[u],v;i;i=nxt[i]) if((v=tar[i]) != ff)
if(ser(v,u,T,id,w)){
Line(id,eid[i],inf,wgt[i]-w);
return 1;
}
return 0;
}
bool SPFA(){
static queue<int>q;
static bool inq[maxn]={};
memcpy(info,buf,sizeof buf);
memset(h,-0x3f,sizeof h);
q.push(T),h[T]=0;
for(int u;!q.empty();){
u=q.front(),q.pop();
for(int i=info[u],v;i;i=Prev[i])if(cap[i^1] && h[v=to[i]] < h[u] + cst[i^1]){
h[v] = h[u] + cst[i^1];
if(!inq[v]) inq[v] = 1 , q.push(v);
}
inq[u] =0;
}
return h[S] > 0;
}
bool vis[maxn];
int aug(int u,int mx){
if(u == T) return ans += h[S] * mx , mx;
int st = mx , inc;
vis[u] = 1;
for(int &i=info[u],v;i;i=Prev[i])
if(cap[i] && h[v=to[i]] + cst[i] == h[u] && !vis[v]){
inc = aug(v,min(cap[i] , st));
cap[i] -= inc , cap[i^1] += inc , st -= inc;
if(!st) return vis[u] =0 , mx - st;
}
vis[u] = 0;
return mx - st;
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d%d",&n,&m);
static int x[maxn],y[maxn],w[maxn],f[maxn],a[maxn],b[maxn];
S = m + 1, T = m + 2;
for(int i=1;i<=m;i++){
scanf("%d%d%d%d%d%d",&x[i],&y[i],&w[i],&f[i],&a[i],&b[i]);
if(f[i]){
Line(i,T,b[i],0);
add(x[i],y[i],i,w[i]);
add(y[i],x[i],i,w[i]);
}
else{
Line(S,i,a[i],0);
}
}
for(int i=1;i<=m;i++)
if(!f[i])
ser(x[i],0,y[i],i,w[i]);
int stm = 0;
for(memcpy(buf,info,sizeof info);SPFA();) stm += aug(S,inf);
printf("%d\n",ans);
}