BZOJ3118 : Orz the MST(對偶費用流)

題目我已經3個月登不上BZOJ了,該不會真的炸了吧

對於線性規劃對偶這一套不熟悉的同學可以看我的這篇博客最後你會發現我還是在讓你去看集訓隊論文

對於我們需要的最小生成樹,首先樹邊只會減小,非樹邊只會增加,考慮所有非樹邊uu,他的兩個端點在樹上的簡單路徑上的所有非樹邊vv,那麼uu的減量du+vd_u+v的增量dvwuwvd_v\geq w_u-w_v

所以可以列出線性規劃:
minimizedubu+dvavs.t.du+dvwuwvdu0\begin{aligned} \rm minimize &\sum d_ub_u + d_va_v \\ s.t.&d_u+d_v \geq w_u - w_v\\ &d_u \geq 0 \end{aligned}

對偶即可得到:
maximizeyu,v(wuwv)s.t.ϕubu,ϕvavdu0\begin{aligned} \rm maximize&\sum y_{u,v}(w_u-w_v) \\ s.t.& \phi_u \leq b_u , \phi_v \leq a_v\\ &d_u \geq 0 \end{aligned}
上面的ϕu\phi_u指的是一個點的出流量和(也是入流量和),也就是說這是一個限制了每個點可以匹配的邊數的最大權匹配,可以用費用流解決。
注意是最大費用流,無需最大流,在SPFASPFAreturnreturn中寫diss0dis_s \geq 0即可。

AC Code\mathrm{AC \ Code}

#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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章