【CF708D】Incorrect Flow(對偶)(單純形)

傳送門

  • 第一次自己玩對偶,少考慮了一個限制調了一萬年,馹,不過還蠻興奮的

minimize:ijxij++xij+yijlimits:vfvi+xvi+xvi=vfiv+xiv+xiv   i[2,n1]fij+xij+xijcij+yijxijfijx+,x,y0minimize:\sum_{ij}x^+_{ij}+x^-_{ij}+y_{ij}\\ limits:\sum_{v}f_{vi}+x^+_{vi}-x^-_{vi}=\sum_{v}f_{iv}+x^+_{iv}-x^-_{iv}~~~\forall i\in[2,n-1]\\\\f_{ij}+x^+_{ij}-x^-_{ij}\le c_{ij}+y_{ij}\\x^-_{ij}\le f_{ij}\\ x^+,x^-,y\ge 0

  • 這顯然是個全幺模矩陣,也就是說最優解可以在整數取得,注意到對偶後不需要初始化

  • 設對偶後的變量爲 tij,zu+,zu,wijt_{ij},z^+_u,z^-_u,w_{ij},則有
    maximize:ijtij(fijcij)+u(zu+zu)(outuinu)+wij(fij)limits:tij+zj+zj+zizi+1tijzj++zjzi+zi+wij1tij1t0,z+0,z,w0maximize:\sum_{ij}t_{ij}(f_{ij}-c_{ij})+\sum_u (z_u^+-z^-_u)(out_u-in_u)+\sum w_{ij}(-f_{ij})\\limits:-t_{ij}+z^+_j-z^-_j+z^-_i-z^+_i\le 1\\ t_{ij}-z_j^++z_j^--z_i^-+z_i^+-w_{ij}\le 1\\ t_{ij}\le 1\\ t\ge 0,z^+\ge 0,z^-,w\ge 0

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int N = 1e3 + 50;
typedef long long ll;
int n, m; ll dg[N];
namespace LP{
	cs double eps = 1e-10, INF = 1e17;
	double a[N][N]; int n, m;
	int id[N];
	void pivot(int l, int e){
		double t=a[l][e]; a[l][e]=1;
		swap(id[l+n],id[e]);
		for(int i=0; i<=m; i++) a[l][i]/=t;
		for(int i=0; i<=n; i++) if(l!=i&&fabs(a[i][e])>0){
			t=a[i][e]; a[i][e]=0;
			for(int j=0; j<=m; j++) a[i][j]-=t*a[l][j];
		}
	}
	int simplex(){
		while(true){
			int l=0, e=0; double mn=INF;
			for(int i=1; i<=m; i++) if(a[0][i]>eps){ e=i; break; }
			if(!e) break; 
			for(int i=1; i<=n; i++) if(a[i][e]>eps&&a[i][0]/a[i][e]<mn) 
			mn=a[i][0]/a[i][e], l=i; if(!l) return -1; //unbounded 
			pivot(l,e);
		} return (ll)-a[0][0];
	}
} using LP::a;
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
	#endif
	scanf("%d%d",&n,&m);
	for(int i=1,u,v,c,f; i<=m; i++){
		scanf("%d%d%d%d",&u,&v,&c,&f);
		a[0][i+m+n+n]=-f;
		a[0][i]=f-c; dg[u]+=f; dg[v]-=f;
		++LP::m; a[LP::m][0]=1; a[LP::m][i]=-1;
		if(v<n) a[LP::m][v+m]=1, a[LP::m][v+m+n]=-1;
		if(u>1) a[LP::m][u+m]=-1, a[LP::m][u+m+n]=1;
		++LP::m; a[LP::m][0]=1; a[LP::m][i]=1; a[LP::m][i+m+n+n]=-1;
		if(v<n) a[LP::m][v+m]=-1, a[LP::m][v+m+n]=1;
		if(u>1) a[LP::m][u+m]=1, a[LP::m][u+m+n]=-1;
	} for(int i=1; i<=m; i++) ++LP::m, a[LP::m][0]=1, a[LP::m][i]=1;
	for(int i=2; i<n; i++) a[0][i+m]=dg[i], a[0][i+m+n]=-dg[i];
	LP::n = m+m+n+n; swap(LP::n, LP::m);
	cout<<LP::simplex(); return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章