对于线性规划对偶这一套不熟悉的同学可以看我的这篇博客最后你会发现我还是在让你去看集训队论文
对于我们需要的最小生成树,首先树边只会减小,非树边只会增加,考虑所有非树边,他的两个端点在树上的简单路径上的所有非树边,那么的减量的增量。
所以可以列出线性规划:
对偶即可得到:
上面的指的是一个点的出流量和(也是入流量和),也就是说这是一个限制了每个点可以匹配的边数的最大权匹配,可以用费用流解决。
注意是最大费用流,无需最大流,在的中写即可。
#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);
}