这是写的很蠢但是很详细的单纯形,为什么蠢呢?因为我竟然给每个基变量开了空间!!写完之后,又看了盾哥的代码!!然后……
// 题目来源:POJ 1273
// 题目大意:求源汇点最大流
// 解决方法:建立线性规划模型,用单纯形求解即可
// 特别注意:设原图有n个点,m条边,则:最大流量约束m,流量平衡约束2*n-4,总约束m+2*n-4;非基变量m,基变量m+2*n-4,总变量2*m+2*n-4;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define eps 0.000001
using namespace std;
double a[1002][1002];
int num[1002];
int n, m;
int main( )
{
while( scanf( "%d%d", &m, &n ) > 0 )
{
memset( a, 0, sizeof( a ) ); // 目标约束矩阵初始化
int aa, bb, cc;
for( int i = 1; i <= m; i++ )
{
scanf( "%d%d%d", &aa, &bb, &cc ); // 读取出端点aa,入端点bb,流量限制cc
a[i][0] = cc;
a[i][i] = -1; // 约束矩阵加入最大流量限制
if( aa != 1 ) a[m+aa-1][i] = -1, a[m+n-3+aa][i] = 1;
if( bb != n ) a[m+bb-1][i] = 1, a[m+n-3+bb][i] = -1; // 约束矩阵加入流量平衡限制
if( aa == 1 ) a[0][i] = 1; // 矩阵首行加入目标函数
}
int var = 2*m + 2*n - 4, bnd = m + 2*n - 4; // 设置变量(variable)与约束(bound)的数量
for( int i = 1; i <= bnd; i++ )
num[i] = i + m; // 给每一约束条件规定基变量
while( 1 )
{
int line = 0, row = 0; // line得到进基变量所在列,row得到出基变量所在行
double delta = 1e30; // 取最紧约束值
for( line = 1; line < var+1; line++ )
if( a[0][line] > eps ) break; // 在目标函数值中找到进基变量
if( line == var+1 ) break; // 无进基变量退出循环
for( int i = 1; i <= bnd; i++ )
if( a[i][line] < -eps && a[i][0] / -a[i][line] < delta )
delta = a[i][0] / -a[i][line], row = i; // 找到被进基变量约束得最紧的基变量,标记为出基变量
a[row][ num[row] ] = -1; // 移项将出基变量改为非基变量
for( int i = 0; i <= var; i++ )
if( i != line ) a[row][i] /= -a[row][line]; // 对出基变量所代表的约束执行恒等变换
a[row][line] = 0; // 取消进基变量的非基属性
num[row] = line; // 给进基变量标记为基变量并代表一个当前约束
for( int i = 0; i <= bnd; i++ )
if( i != row && a[i][line] != 0 )
{
for( int j = 0; j <= var; j++ )
if( j != line ) a[i][j] += a[row][j] * a[i][line]; // 对所有约束执行消元
a[i][line] = 0; // 消元操作
}
}
printf( "%.0lf\n", a[0][0] ); // 输出目标函数当前值
}
return 0;
}
诶,还是太蠢了,反正需要利用的只有非基变量,也就是说每次需要表示出来的变量总是那么多!那我恒等变形的时候只要覆盖就可以了嘛!!再跪盾哥。
优化后的code:
// 题目来源:POJ 1273
// 题目大意:求源汇点最大流
// 解决方法:建立线性规划模型,用单纯形求解即可
// 特别注意:设原图有n个点,m条边,则:最大流量约束m,流量平衡约束2*n-4,总约束m+2*n-4;变量m;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define eps 0.000001
using namespace std;
double a[1002][1002];
int num[1002];
int n, m;
int main( )
{
while( scanf( "%d%d", &m, &n ) > 0 )
{
memset( a, 0, sizeof( a ) ); // 目标约束矩阵初始化
int aa, bb, cc;
for( int i = 1; i <= m; i++ )
{
scanf( "%d%d%d", &aa, &bb, &cc ); // 读取出端点aa,入端点bb,流量限制cc
a[i][0] = cc;
a[i][i] = -1; // 约束矩阵加入最大流量限制
if( aa != 1 ) a[m+aa-1][i] = -1, a[m+n-3+aa][i] = 1;
if( bb != n ) a[m+bb-1][i] = 1, a[m+n-3+bb][i] = -1; // 约束矩阵加入流量平衡限制
if( aa == 1 ) a[0][i] = 1; // 矩阵首行加入目标函数
}
int bnd = m + 2*n - 4; // 设置约束(bound)的数量
while( 1 )
{
int line = 0, row = 0; // line得到进基变量所在列,row得到出基变量所在行
double delta = 1e30, k; // 取最紧约束值
for( line = 1; line < m+1; line++ )
if( a[0][line] > eps ) break; // 在目标函数值中找到进基变量
if( line == m+1 ) break; // 无进基变量退出循环
for( int i = 1; i <= bnd; i++ )
if( a[i][line] < -eps && a[i][0] / -a[i][line] < delta )
delta = a[i][0] / -a[i][line], row = i; // 找到被进基变量约束得最紧的基变量,标记为出基变量
k = -a[row][line]; // 取进基变量系数的相反数
a[row][line] = -1; // 将出基变量覆盖进基变量完成出基操作
for( int i = 0; i <= m; i++ )
a[row][i] /= k; // 对出基变量所代表的约束执行恒等变换
for( int i = 0; i <= bnd; i++ )
if( i != row && a[i][line] != 0 )
{
k = a[i][line], a[i][line] = 0;
for( int j = 0; j <= m; j++ )
a[i][j] += a[row][j] * k; // 对所有约束执行消元
}
}
printf( "%.0lf\n", a[0][0] ); // 输出目标函数当前值
}
return 0;
}
这样优化以后,空间瞬间变为原来的四分之一(大约嗯),虽然我的数组还是开了这么多。
本来觉得吧,单纯形这打起来蛋疼的算法,到底为什么值得我们去学习呢,空间消耗这么大!原来……是我打的太丑了,这样弄一下好了不知道多少了啊!!爱打多了!!