鏈接:
#include <stdio.h>
int main()
{
puts("轉載請註明出處[vmurder]謝謝");
puts("網址:blog.csdn.net/vmurder/article/details/45673079");
}
題解:
這道題是線性規劃求目標函數最小值 ,對偶原理轉一下就成了單純形算法求線性規劃最大值。
單純形法:
首先這篇博客缺失了很多證明,只能講述單純形法的實現。
// N個變量 M個限制
double a[M][N]; // 這m個限制裏變量的係數
double b[M]; // 第i個限制加和 <=bi
double c[N]; // 目標函數裏變量係數
double ans; // 目標函數自帶的係數
void pivot(int x,int y); // 轉軸操作
void solve();
首先對於如下數據
3 3
2 3 4
1 1 2 2
1 2 3 5
1 3 3 2
我們可以得到以下的限制:
目標函數:
限制函數:
然後若
那麼我們可以將式子表示爲
狀態 1: **************
目標函數:
限制函數:
然後在單純形的過程中函數們的各系數得到改變的過程如下:
狀態 1: **************
目標函數:
限制函數:
狀態 2: **************
目標函數:
限制函數:
狀態 3: **************
目標函數:
限制函數:
狀態 4: **************
目標函數:
限制函數:
狀態 5: **************
目標函數:
限制函數:
線性規劃最終答案:17
單純形思想:
其實就是每次找一個在目標函數中存在的變量,跟不在其中的某個變量交換一下,然後換來換去最終目標函數中所有變量係數都爲負了,那麼目標函數最後加的常數就是答案辣。
單純形實現:
具體的實現過程呢?
struct Simplex
{
int n,m; // n個變量、m個限制
double a[M][N],b[M],c[M],ans;
void pivot(int x,int y)
{
int i,j;
double t;
b[x]/=a[x][y];
for(i=1;i<=n;i++)if(i!=y)a[x][i]/=a[x][y];
a[x][y]=1.0/a[x][y];
for(i=1;i<=m;i++)if(i!=x&&fabs(a[i][y])>eps)
{
b[i]-=a[i][y]*b[x],t=a[i][y];
for(j=1;j<=n;j++)a[i][j]-=t*a[x][j];
a[i][y]=-t*a[x][y];
}
ans+=c[y]*b[x],t=c[y];
for(i=1;i<=n;i++)c[i]-=t*a[x][i];
c[y]=-t*a[x][y];
}
double solve()
{
read();
double t;
for(int i,x,y;;)
{
for(i=1;i<=m;i++)if(c[i]>eps){y=i;break;}
if(i>m)return ans;
for(t=inf,i=1;i<=m;i++)
if(a[i][y]>eps&&t>b[i]/a[i][y])
x=i,t=b[i]/a[i][y];
if(t==inf)return t;
else pivot(x,y);
}
}
}simplex;
下面的實現裏存在兩個坑,請不要深究它們怎麼證。
首先我們每次找一個標號最靠前的【坑1】目標函數中係數爲正的變量
然後我們找這個變量在哪個限制裏是”最緊”的【坑3】,即33、34、35這三行。
如果找不到任何一個”緊”的行,即
然後我們對此限制中的輔助變量和找到的
先把第
對偶原理:
如果要求最小值,那麼我們把模型對偶一下就可以辣。【坑5】
即限制矩陣 【轉置】 一下,然後目標函數的係數和每個限制的最終
【轉置】 :矩陣的元素
對於證明坑的總結:
【坑1】爲什麼要找標號最小的?
根據Bland法則,這麼做可以避免被卡死循環。
【坑2】爲什麼標號都是負的就表示找到了最優解?
表示無法理解爲什麼不能給某個存在負係數的變量轉一轉。
【坑3】爲什麼要找”最緊”的?
不知道不知道。
【坑4】爲什麼直接返回無界了?
不可以別的某個變量再來轉一轉,然後就迴歸有界?
【坑5】對偶原理是毛線?
天然坑,深坑。
代碼:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1010 // 變量個數
#define M 10100 // 限制個數
#define inf 1e9
#define eps 1e-5
using namespace std;
struct Simplex
{
int n,m; // n個變量、m個限制
double a[M][N],b[M],c[M],ans;
void read()
{
int i,j,k,l,r;
scanf("%d%d",&m,&n);
for(i=1;i<=m;i++)scanf("%lf",&c[i]);
for(i=1;i<=n;i++)
{
scanf("%d",&k);
while(k--)
{
scanf("%d%d",&l,&r);
for(j=l;j<=r;j++)a[i][j]=1.0;
}
scanf("%lf",&b[i]);
}
swap(n,m);
}
void pivot(int x,int y)
{
int i,j;
double t;
b[x]/=a[x][y];
for(i=1;i<=n;i++)if(i!=y)a[x][i]/=a[x][y];
a[x][y]=1.0/a[x][y];
for(i=1;i<=m;i++)if(i!=x&&fabs(a[i][y])>eps)
{
b[i]-=a[i][y]*b[x],t=a[i][y];
for(j=1;j<=n;j++)a[i][j]-=t*a[x][j];
a[i][y]=-t*a[x][y];
}
ans+=c[y]*b[x],t=c[y];
for(i=1;i<=n;i++)c[i]-=t*a[x][i];
c[y]=-t*a[x][y];
}
double solve()
{
read();
double t;
for(int i,x,y;;)
{
for(i=1;i<=m;i++)if(c[i]>eps){y=i;break;}
if(i>m)return ans;
for(t=inf,i=1;i<=m;i++)
if(a[i][y]>eps&&t>b[i]/a[i][y])
x=i,t=b[i]/a[i][y];
if(t==inf)return t;
else pivot(x,y);
}
}
}simplex;
int main()
{
// freopen("test.in","r",stdin);
printf("%d\n",(int)(simplex.solve()+eps));
return 0;
}