1. 程式人生 > 其它 >單純形法與對偶定理

單純形法與對偶定理

這貌似是運籌學的一個比較有趣的問題型別
不過介於我水平太低(只會背背板子)
在此記錄

單純形法

一般oi中遇到的線性規劃問題都長這樣

比如某一些網路流問題,以及二分圖最大權匹配啥的,結合對偶定理,可以有很多很強的結論

以及一個最小費用流的線性規劃式子

現在考慮怎麼做這類問題

不妨先引入一個基變數(鬆弛變數)


比如說現在的係數矩陣是
比如說現在的係數矩陣是

\[\left\{ \begin{matrix} x_{11} & x_{12} & x_{13} & x_{14} & ... &x_{1n + 1}\\ x_{21} & x_{22} & x_{23} & x_{24} & ... &x_{2n + 1}\\ x_{31} & x_{32} & x_{33} & x_{34} & ... &x_{3n + 1}\\ x_{41} & x_{42} & x_{43} & x_{44} & ... &x_{4n + 1}\\ . ..\\ x_{m1} & x_{m2} & x_{m3} & x_{m4} & ... &x_{mn + 1}\\ \end{matrix} \right\}\\ 對於第i行\\ x_{i,n+1} = b_i - \sum_{j = 1}^nx_{i , j} * a_{i , j}\\ 不妨將第x_{i , k}表示出來\\ x_{i , k} = \frac{x_{i , n + 1} + \sum_{j\ !=\ k}x_{i , j} * a_{i , j} - b_i}{-a_{i , k}}\\ 給你要最大化的式子帶來的價值是\\ \frac{x_{i , n + 1} + \sum_{j\ !=\ k}x_{i , j} * a_{i , j} - b_i}{-a_{i , k}} * val_k\\ \]

這樣可以吧\(x_{i , n + 1}\)

的值給去\(x_{i , k}\),這樣的操作叫做轉軸

之後就可以用這個過程來時目標函式有最大值

有一個例題吧

很容易列出線性規劃式子

\[\left\{ \begin{matrix} max:c_1 * x_1 + c_2 * x_2 + ... + c_n *x_n\\ a_{11} * x_1 + a_{12} * x_2 + ... + a_{1n} * x_n <= b_1\\ .\\ .\\ a_{m1} * x_1 + a_{m2} * x_2 + ... + a_{mn} * x_n <= b_m\\ \end{matrix} \right. \]

就是一個板子題

#include<bits/stdc++.h>
#define MAXN 500
#define eps 1e-7
typedef double ll;
const ll inf  = 1e18;
using namespace std;

int n,m;
ll a[MAXN][MAXN];
int id[MAXN];

void out(){
	for(int i = 1 ; i <= n ; i++)printf("%.2f " , a[0][i]);
	puts("");
	for(int i = 1 ; i <= m ; i++){
		for(int j = 1 ; j <= n ; j++){
			printf("%.2f " , a[i][j]);
		}
		printf("%.2f " , a[i][0]);
		puts("");
	}
}

void plot(int x , int y){
	swap(id[x + n] , id[y]);
	double t = a[x][y];	a[x][y] = 1;
	for(int j = 0 ; j <= n ; j++)a[x][j] /= t;
	for(int i = 0 ; i <= m ; i++){
		if(i == x || a[i][y] < eps)continue;
		t = a[i][y] , a[i][y] = 0;
		for(int j = 0 ; j <= n ; j++)a[i][j] -= a[x][j] * t;
	}
}

bool simplex(){
	for(int i = 1 ; i <= n ; i++)id[i] = i;
	int x = 0, y = 0;
	int cnt = 0;
	ll minl;
	while(1){
		x = y = 0 , minl = inf;
		cnt++;
		for(int i = 1 ; i <= n ; i++)if(a[0][i] > eps){x = i;break;}
		if(!x)break;
		for(int i = 1 ; i <= m ; i++)if(a[i][x] > eps && minl > a[i][0] / a[i][x])minl = a[i][0] / a[i][x] , y = i;
		if(!y) {puts("Unbounded"); return false;}
		plot(y , x);
	}
	return true;
}

int main(){
	while(scanf("%d%d",&n,&m) == 2){
		memset(a , 0 ,sizeof(a));
		for(int i = 1 ; i <= n ; i++)cin>>a[0][i];
		for(int i = 1 ; i <= m ; i++){
			for(int j = 1 ; j <= n ; j++)cin>>a[i][j];
			cin>>a[i][0];
		}
		simplex();
		printf("Nasa can spend %d taka.\n",(int)ceil(-a[0][0]*m));	
	}
}

對偶定理

很容易寫出線性規劃的模型,及其對偶
其係數矩陣為原係數矩陣的轉置



原問題有無界解等價於對偶問題無可行解

但是對偶問題無可行解時,原問題可能為無界解或者無可行解

剩下的很多擴充套件內容可以看這個
https://www.cnblogs.com/TianyiQ/p/linear-programming.html