《趣学算法》 第七章线性规划网络流代码实现(Java)

7.2 单纯形算法

import java.util.Scanner;

public class Test7_1 {
	
	static int n,m,i,j;                                              //m表示非基本变量个数即矩阵的列数,n表示基本变量个数即矩阵的行数
	static int[] FJL=new int[100];                                   //存放非基本变量
	static int[] JL=new int[100];                                    //存放基本变量
	static float[][] kernel=new float[100][100];                     //存放单纯形表
	 
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		System.out.println("输入非基本变量个数和非基本变量下标:");   
		m=scanner.nextInt();
		for(int i=1;i<=m;i++)
			FJL[i]=scanner.nextInt();
		System.out.println("输入基本变量个数和基本变量下标:");
		n=scanner.nextInt();
		for(int i=1;i<=n;i++)
			JL[i]=scanner.nextInt();
		System.out.println("输入约束标准型初始单纯形表参数:");
		for(int i=0;i<=n;i++) {
			for(int j=0;j<=m;j++)
				kernel[i][j]=scanner.nextFloat();                    //检验数放第一行,常数项放第一列,非基本变量的系数作为值
		}
		print();                                                     //输出单纯形表
		DCXA();
		scanner.close();
	}
	
	/*输出单纯形表*/
	public static void print() {
		System.out.println();
		System.out.println("单纯形表如下:");
		System.out.print("	"+"b	");
		for(i=1;i<=m;i++)
			System.out.print("x"+FJL[i]+"	");
		System.out.println();
		System.out.println("c	");
		for(i=0;i<=n;i++) {
			if(i>=1)
				System.out.print("x"+JL[i]+"	");
			for(j=0;j<=m;j++)
				System.out.print(kernel[i][j]+"	 ");
			System.out.println();
		}
	}
	
	/*求解函数*/
	public static void DCXA() {
		float max1;                                                    //用于存放最大的检验数
		float max2;                                                    //用于存放最大正检验数对应的基本变量的最大系数
		int e=-1;                                                      //记录入基列
		int k=-1;                                                      //记录离基行
		float min;
		
		while(true) {                                                  //循环迭代,直到直到问题的解或无解
			max1=0;
			max2=0;
			min=10000000;
			
			for(j=1;j<=m;j++) {                                        //找入基列,即正检验数中最大的为入基变量,所在列为入基列
				if(max1<kernel[0][j]) {
					max1=kernel[0][j];
					e=j;                                               //记录入基列的列下标
				}
			}
			if(max1<=0) {                                              //所有的检验值小于等于0,获得最优解
				System.out.println("获得最优解:"+kernel[0][0]);
				break;
			}
			
			for(i=1;i<=n;i++) {                                        //找离基行,常数列/入基列正比值最小对应的行
				if(max2<kernel[i][e])                                  //入基列中的最大系数
					max2=kernel[i][e];
				
				float temp=kernel[i][0]/kernel[i][e];                  //常数项/入基列
				temp=Math.abs(temp);
				if(temp>0&&temp<min) {
					min=temp;                                          //找比值最小
					k=i;                                               //记录离基行的行下标
				}
			}
			System.out.println("基列变量:x"+FJL[e]);
			System.out.println("离基变量:x"+JL[k]);
			if(max2==0) {                                              //无解
				System.out.println("解无界");
				break;
			}
			
			//将入基变量和离基变量互换位置
			int temp=FJL[e];
			FJL[e]=JL[k];
			JL[k]=temp;
			
			//计算单纯形表
			for(i=0;i<=n;i++) {                                        //计算除入基列和离基行的所有位置的元素
				if(i!=k) {                                             //非离基行
					for(j=0;j<=m;j++) {
						if(j!=e) {                                     //非入基列
							if(i==0&&j==0)
								kernel[i][j]=kernel[i][j]+kernel[i][e]*kernel[k][j]/kernel[k][e];             //计算特殊位置c0位
							else
								kernel[i][j]=kernel[i][j]-kernel[i][e]*kernel[k][j]/kernel[k][e];             //一般位置
						}
					}
				}
			}
			for(i=0;i<=n;i++) {                                         //计算入基列的元素
				if(i!=k)                                                //非交叉位
					kernel[i][e]=-kernel[i][e]/kernel[k][e];
			}
			
			for(j=0;j<=m;j++) {                                         //计算离基行的元素
				if(j!=e)                                                //非交叉位
					kernel[k][j]=kernel[k][j]/kernel[k][e];
			}
			kernel[k][e]=1/kernel[k][e];                                //计算交叉位置
			print();
			
		}
	}

}

程序运行结果如下:


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值