UOJ197 线性规划

传送门

由于这道题标程GG了所以必不可能AC嘛2333

单纯形法是一个很玄学的东西qwq

就是 非标准型 -> 标准型 -> 规范型 -> 松弛型

一个玄学操作——转轴操作(privot)

等着学习笔记到时候再补吧先把程序放出来

写了一些注释方便理解qwq

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctime>
#define inf 20021225
#define ll long long
#define db double
#define eps 1e-8
using namespace std;

db ans[51],a[51][51];int id[51];int n,m,t;

void privot(int x,int y)
{
	swap(id[n+x],id[y]);
	// 把基变量和非基变量只交换编号
	// 相当于 id[n+x] x∈(1,m) 存基变量的编号 
	db tmp=1.0/a[x][y];
	a[x][y]=1.0;// 原先基变量系数为1 
	for(int i=0;i<=n;i++)	a[x][i]*=tmp;
	// 非基变量化基变量系数化一  类似解方程代入法之前的系数化一 
	for(int i=0;i<=m;i++)
	{
		if(i==x||abs(a[i][y])<eps)	continue;
		db cur=a[i][y]; a[i][y]=0.0;
		for(int j=0;j<=n;j++)
			a[i][j]-=a[x][j]*cur;
	}
	// 利用新的基变量消元 
}

bool prework()
{
	// 规范型线性规划要求b[i]非负 但是标准型没有这个要求 所以需要预处理 
	// 把所有b[i]是负的随机匹配几个a[i]是负的然后替换一下 b[i]就变成正的了 
	while(1)
	{
		int x=0,y=0,i;
		for(i=1;i<=m;i++)	if(a[i][0]<-eps && (!x || rand()&1)) x=i;
		if(!x)	return true;
		for(i=1;i<=n;i++)	if(a[x][i]<-eps && (!y || rand()&1)) y=i;
		if(!y){printf("Infeasible\n");return false;}//只能取负数无可行域
		privot(x,y);
	}
	return true;
}

bool simplex()
{
	while(1)
	{
		int i,x=0,y=0; double mn=1e15;
		for(i=1;i<=n;i++)	if(a[0][i]>eps){y=i;break;}
		// 找一个目标系数>0的 
		if(!y)	break;
		for(i=1;i<=m;i++)
			if(a[i][y]>eps&&a[i][0]/a[i][y]<mn)
				mn=a[i][0]/a[i][y],x=i;
		// 找限制最严格的 
		if(!x){printf("Unbounded\n");return false;} 
		// 没有限制直接上天(划)无穷大 
		privot(x,y);
	}
	return true;
}

int main()
{
	srand(time(0));
	scanf("%d%d%d",&n,&m,&t);
	for(int i=1;i<=n;i++)	scanf("%lf",&a[0][i]),id[i]=i;
	//初始非基变量i 基变量n+i 
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)	scanf("%lf",&a[i][j]);
		scanf("%lf",&a[i][0]);
	}
	if(prework()&&simplex())
	{
		printf("%.8lf\n",-a[0][0]);
		if(t)
		{
			for(int i=1;i<=m;i++)	ans[id[n+i]]=a[i][0];
			for(int i=1;i<=n;i++)	printf("%.8lf ",ans[i]);
		}
	} 
	return 0;
}

 

posted @ 2018-12-06 11:07  寒雨微凝  阅读(190)  评论(0编辑  收藏  举报