这是写的很蠢但是很详细的单纯形,为什么蠢呢?因为我竟然给每个基变量开了空间!!写完之后,又看了盾哥的代码!!然后……
// 题目来源: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; }这样优化以后,空间瞬间变为原来的四分之一(大约嗯),虽然我的数组还是开了这么多。
本来觉得吧,单纯形这打起来蛋疼的算法,到底为什么值得我们去学习呢,空间消耗这么大!原来……是我打的太丑了,这样弄一下好了不知道多少了啊!!爱打多了!!