POJ 1273 Drainage Ditches (最大流,线性规划)

/*题目大意:有N条排水管道连接编号为1~N个的节点,从Si到Ei的排水管道的最大容量是Ci。输入第一行N , M ,接着又N行,分别是每条排水管道的Si,Ei,Ci。求:从节点1到节点M最大能够通过的流量是多少。*/

 

/*这是一道很明显的最大流问题,可以用网络流算法来稿,还可以用线性规划来做。我用线性规划来搞的。*/

 

/*节点的流入流出以及管道的最大容量为约束条件,每条水管通过的流量为变量*/

/*

设Xi表示第i条水管的实际流量,设节点 j 有Xj1 ~ Xjp 流入Xk1 ~ Xkq 流出(1<j<M;{  Xj1  ,  Xj2  ,  Xj3  .....Xjp  }属于  X  ,  { Xk1 , Xk2 , Xk3 .....Xkp }属于 X)

 

可以构造下列的约束方程组:

Xi < =Ci  ;      ----------------------------------------------------------------------------------------------------------------(1 < = i < = N)

( Xj1 + Xj2 + . . . + Xjp ) - ( Xk1 + Xk2 + . . . + Xkp ) < = 0 ; ---------------------------------------------------------(1 < j < M)

( Xk1 + Xk2 + . . . + Xkp ) - ( Xj1 + Xj2 + . . . + Xjp ) < = 0 ; ---------------------------------------------------------(1 < j < M)

( X11 + X12 + . . . + X1p ) - ( Xm1 + Xm2 + . . . + Xmp ) < = 0 ;

( Xm1 + Xm2 + . . . + Xmp ) - ( X11 + X12 + . . . + X1p ) < = 0 ;

 

目标函数:C=Xm1+Xm2+...+Xmp;

 

(注意:对于开始节点1和结束节点N,如果有直接连接的话,( X11 + X12 + . . . + X1p )和( Xm1 + Xm2 + . . . + Xmp )中有重复的元素,也就是说,做减法之后,某一个或几个Xi的系数就是0,所以转换的时候要注意!!!)

 

 

Source Code

Problem: 1273 User: imutzcy
Memory: 1184K Time: 63MS
Language: C++ Result: Accepted

  • Source Code
    #include<functional>
    #include<algorithm>
    #include<iostream>
    #include<fstream>
    #include<sstream>
    #include<iomanip>
    #include<numeric>
    #include<cstring>
    #include<cassert>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<bitset>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<ctime>
    #include<list>
    #include<set>
    #include<map>
    
    using namespace std;
    
    
    /*const int r=2;//原线性规划问题中的变量个数,即:松弛变量前的变量个数 */
    int r;
    
    /*const int m=3;//先行约束条件个数 */
    int m;
    
    const double eps=1e-6;
    
    /*const double Max=1<<30;*/
    const double Max=1e10;
     
    /*double matrix[m+2][r+2];//d单纯性算法的表格  */
    double matrix[610][210];
    
    int flag;
    /*
    flag = = 0 , 表示目标函数的最大值无边界,一般认为无解;
    flag = = 1,  表示有唯一的最优基本可行解
    flag = = 2, 表示目标函数值确定,但最优的基本可行解不唯一
    */
    
    int main()
    {
        int N,M,from,to,flow;
        while(~scanf("%d%d",&N,&M)){
        //N边,有N个变量;M顶点,有2M+N个约束; 
          r=N;
          m=2*M+N;
          memset(matrix,0,sizeof(matrix));
          for(int i=1;i<=N;i++){
            scanf("%d%d%d",&from,&to,&flow);
          //边的流量小于最大容量
            matrix[2*M+i][i]=1;
            matrix[2*M+i][r+1]=flow;
          
          //流入等于流出,用 < =和 > = 表示等于...  注释(1)
            if(from!=1){
              matrix[from*2-1][i]=-1;
              matrix[from*2][i]=1;;
            }
            else if(to!=M){
          //注意特殊的开始节点和结束节点,是所有从开始流出的等于从结束流入的
          //这里用第 2 * M 和 2 * M - 1 个约束表示这种关系
          //同时,要注意的是,直接从开始到结束点的边要除外,否则会造成标记错误...注释(2)
              matrix[2*M][i]=1;
              matrix[2*M-1][i]=-1;
          }
          
          //同注释(1)
            if(to!=M){
              matrix[to*2][i]=-1;
              matrix[to*2-1][i]=1;
            }
            else{
              if(from!=1){
            //同注释(2)
                matrix[2*M][i]=-1;
                matrix[2*M-1][i]=1;
              }
            //目标函数,C=Xa+Xb+Xc+...+Xz , Xa+Xb+Xc+..+Xz为所有连向结束节点的边,求MAX(C)
              matrix[m+1][i]=-1;
            }
            matrix[0][i]=i;//标记边的序号,最后可以输出解的细节
          }
        
        /* 
        //松弛变量,初始一个基本可行解之后的表格
        for(int i=1;i<=m+1;i++)
          for(int j=1;j<=r+1;j++)
            scanf("%lf",&matrix[i][j]);
        */
        
          while(1){
            flag=1;
          //寻找非基本变量
            int ru;
            for(ru=1;ru<=r+1;ru++)
              if(matrix[m+1][ru]<0) break;
            
          //若找不到合适的非基本变量,说明目标函数已最优
            if(ru>r+1) break;
          /*
          if(ru>r+1){
          //判断最优基本可行解是否唯一
            for(ru=1;ru<=r+1;ru++){
              if(matrix[m+1][ru]<eps&&matrix[m+1][ru]>-eps){
                flag=2;
                break;
              }
            }
            break;
          }
          */
          
            double Min=Max;
          //寻找基本变量
            int chu;
            for(int j=1;j<=m;j++){
              if(matrix[j][ru]>0){
                double tmp=matrix[j][r+1]/matrix[j][ru];
                if(tmp<Min){
                  Min=tmp;
                  chu=j;
                }
              }
            }
          
          /*
          //如果找不到合适的基本变量,说明目标函数无界
          if(fabs(Min-Max)<eps){
            flag=0;
            break;
          }
          */
          
          //此题不会出现无解情况
          //交换非基本变量和基本变量名字
            double tmp=matrix[chu][0];
            matrix[chu][0]=matrix[0][ru];
            matrix[0][ru]=tmp;
          
          //先修改表格matrix[chu][ru]
            matrix[chu][ru]=1.0/matrix[chu][ru];
          
          //修改表格的主元行
            for(int j=1;j<=r+1;j++){
              if(j==ru) continue;
              matrix[chu][j]*=matrix[chu][ru];
            }
          
          //修改表格中其他单元格
            for(int i=1;i<=m+1;i++){
              if(i==chu) continue;
              for(int j=1;j<=r+1;j++){
                if(j==ru) continue;
                matrix[i][j]-=matrix[chu][j]*matrix[i][ru];
              }
            }
          
          //修改表格中主元列
            for(int j=1;j<=m+1;j++){
              if(j==chu) continue;
              matrix[j][ru]=-matrix[j][ru]*matrix[chu][ru];
            }
          }
        
        /*
        解集读取(只是其中一个解,没有多解的情况判断);
        for(int i=1;i<=r;i++)
          if(matrix[0][i]!=0.0)
            printf("x%.0lf=%.2lf\n",matrix[0][i],matrix[m+1][i]);
        
        for(int i=1;i<=m;i++)
          if(matrix[i][0]!=0.0)
            printf("x%.0lf=%.2lf\n",matrix[i][0],matrix[i][r+1]);
        
        printf("\n"); 
        
        */
        
        
        /*
        if(flag==0) printf("该目标函数无界\n");
        
        else if(flag==1) printf("该目标函数有一个最优基本可行解,最优值为%lf\n",matrix[m+1][r+1]);
        
        else printf("该目标函数有不止一个最有基本可行解,最优值为%lf\n",matrix[m+1][r+1]);
        
        system("pause");
        
        */
        
          printf("%.0lf\n",matrix[m+1][r+1]);
        }
        return 0;
    }
    

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值