zoukankan      html  css  js  c++  java
  • 线性规划初探

    看完《算法导论》肯定会写单纯形

    因为单纯形不仅好写而且《算法导论》里讲的很清楚

    附赠uoj179的模板一个

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 #include<stdlib.h>
     7 
     8 using namespace std;
     9 const double eps=1e-9;
    10 double a[50][50];
    11 int b[50],u[50],n,m,ty;
    12 
    13 int read()
    14 {
    15     int x=0,f=1;char ch=getchar();
    16     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    17     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    18     return x*f;
    19 }
    20 int dcmp(double x)
    21 {
    22     if (fabs(x)<=eps) return 0;
    23     if (x>0) return 1; else return -1;
    24 }
    25 
    26 void pivot(int x,int y)
    27 {
    28      swap(b[x],u[y]);
    29      double k=a[x][y]; a[x][y]=1;
    30      for (int i=0; i<=n; i++) a[x][i]/=k;
    31      for (int i=0; i<=m; i++)
    32        if (i!=x&&dcmp(a[i][y])!=0)
    33        {
    34           k=a[i][y]; a[i][y]=0;
    35           a[i][0]+=(i?-1:1)*k*a[x][0];
    36           for (int j=1; j<=n; j++)
    37             a[i][j]-=k*a[x][j];
    38        }
    39 }
    40 bool initial()
    41 {
    42      for (int i=1; i<=n; i++) u[i]=i;
    43      for (int i=1; i<=m; i++) b[i]=n+i;
    44      while (1)
    45      {
    46            int x=0,y=0;
    47            for (int i=1; i<=m; i++)
    48              if (dcmp(a[i][0])<0) x=i;
    49            if (!x) return 1;
    50            for (int i=1; i<=n; i++)
    51              if (dcmp(a[x][i])<0) y=i;
    52            if (!y) return 0;
    53            pivot(x,y);
    54      }  
    55 }
    56                
    57 int simplex()
    58 {
    59     if (!initial()) return 0;
    60     while (1)
    61     {
    62           int x=0,y=0; 
    63           for (int i=1; i<=n; i++)
    64             if (dcmp(a[0][i])>0) {y=i; break;}
    65           if (!y) return 1;
    66           double mi=1e15;
    67           for (int i=1; i<=m; i++)
    68             if (dcmp(a[i][y])>0&&(!x||a[i][0]/a[i][y]<mi)) {mi=a[i][0]/a[i][y];x=i;}
    69           if (!x) return -1;
    70           pivot(x,y);
    71     }  
    72 }          
    73 int main()
    74 {
    75     n=read(); m=read(); ty=read(); 
    76     for (int i=1; i<=n; i++) a[0][i]=read();
    77     for (int i=1; i<=m; i++)
    78     {
    79         for (int j=1; j<=n; j++) a[i][j]=read(); 
    80         a[i][0]=read();
    81     }
    82     switch (simplex())
    83     {
    84            case 1:{
    85                 printf("%.8lf
    ",a[0][0]);
    86                 if (ty)
    87                 {
    88                    for (int i=1; i<=n; i++) u[i]=0;
    89                    for (int i=1; i<=m; i++) if (b[i]<=n) u[b[i]]=i;
    90                    for (int i=1; i<=n; i++) printf("%.8lf ",u[i]?a[u[i]][0]:double(0));
    91                 }
    92                 break;
    93            }
    94            case 0:puts("Infeasible");break;
    95            case -1:puts("Unbounded");break;
    96     }
    97     system("pause");
    98     return 0;
    99 }
    View Code

    据说会被卡但实际上基本跑得飞起(下面会用实例证明)

    下面是实际应用,凡是最大流,费用流的问题大概都能用线性规划解决,而且会很快变裸题……

    比如这个1061,很明显把每天的要求人数bi作为约束,每种志愿者雇佣数量做变量xi

    也就是求最小化∑ci*xi i=1..m

    并且x要满足约数条件 ∑aij*xi>=bi i=1..n, j=1..m, ai,j=(sj<=i<=ti)?1:0,且xj非负

    但是这与标准线性规划刚好相反,标准应该是全是<=且最大化

    当然如果你看过《算法导论》关于单纯形最优解证明的话,你就会知道在对偶线性规划下这很简单

    对于标准型线性规划:最大化∑ci*xi i=1..n ∑aij*xi<=bi i=1..m, j=1..n,x非负

    我们很容易转化成对偶情况:最小化∑bi*xi i=1..m, ∑aij*xi>=bi i=1..n, j=1..m,x非负

    这两种线性规划最优值相等(不禁联想到最大流和最小割的关系)

    于是我们直接上单纯形即可

    但是也许有疑虑,n<=1000,m<=10000能过吗&……

    然而答案是c++版本的单纯形跑了1212ms,而我以前pascal版本的费用流跑了1764ms,

    所以单纯形还是非常非常厉害的,大胆的使用吧……

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath> 
     5 #include<stdlib.h> 
     6 
     7 using namespace std;
     8 const double eps=1e-9;
     9 int b[11100],u[11100],n,m;
    10 double a[10010][1010];
    11 
    12 int dcmp(double x)
    13 {
    14     if (fabs(x)<=eps) return 0;
    15     if (x>0) return 1; else return -1;
    16 }
    17 
    18 void pivot(int x,int y)
    19 {
    20      swap(b[x],u[y]);
    21      double k=a[x][y];a[x][y]=1;
    22      for (int i=0; i<=n; i++) a[x][i]/=k;
    23      for (int i=0; i<=m; i++)
    24          if (i!=x&&dcmp(a[i][y])!=0)
    25          {
    26             k=a[i][y]; a[i][y]=0;
    27             a[i][0]+=(i?-1:1)*k*a[x][0];
    28             for (int j=1; j<=n; j++) a[i][j]-=k*a[x][j];
    29          }
    30 }
    31                 
    32 void simplex()
    33 {
    34      for (int i=1; i<=n; i++) u[i]=i;
    35      for (int i=1; i<=m; i++) b[i]=i+n;
    36      while (1)
    37      {
    38            int x=0,y=0;
    39            for (int i=1; i<=n; i++)
    40              if (dcmp(a[0][i])>0) {y=i;break;}
    41            if (!y) break;
    42            double mi=1e20;
    43            for (int i=1; i<=m; i++)
    44              if (dcmp(a[i][y])>0&&(!x||mi>a[i][0]/a[i][y])) {x=i; mi=a[i][0]/a[i][y];}
    45            if (!x) break;
    46            pivot(x,y);
    47      }  
    48 }           
    49      
    50 int main()
    51 {
    52     scanf("%d%d",&n,&m);
    53     for (int i=1; i<=n; i++) scanf("%lf",&a[0][i]);
    54     for (int i=1; i<=m; i++)
    55     {
    56         int s,t,c;
    57         scanf("%d%d%d",&s,&t,&c);
    58         for (int j=s; j<=t; j++) a[i][j]=1;
    59         a[i][0]=c;
    60     }
    61     simplex();
    62     printf("%d
    ",(int)a[0][0]);
    63     system("pause");
    64     return 0;
    65 }
    1061

     bzoj3112 题目在这里http://blog.csdn.net/popoqqq/article/details/44312949

    很显然和1061大同小异

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<stdlib.h>
     7 
     8 using namespace std;
     9 const double eps=1e-9;
    10 double a[1010][10010];
    11 int n,m;
    12 
    13 int dcmp(double x)
    14 {
    15      if (fabs(x)<=eps) return 0;
    16      if (x>0) return 1; else return -1;
    17 }
    18 
    19 void pivot(int x,int y)
    20 {
    21      double k=a[x][y]; a[x][y]=1;
    22      for (int i=0; i<=n; i++) a[x][i]/=k;
    23      for (int i=0; i<=m; i++)
    24        if (i!=x&&dcmp(a[i][y])!=0)
    25        {
    26           k=a[i][y]; a[i][y]=0;
    27           a[i][0]+=(i?-1:1)*k*a[x][0];
    28           for (int j=1; j<=n; j++) a[i][j]-=k*a[x][j];
    29        }
    30 }
    31 void simplex()
    32 {
    33      while (1)
    34      {
    35            int x=0,y=0;
    36            for (int i=1; i<=n; i++)
    37              if (dcmp(a[0][i])>0) {y=i;break;}
    38            if (!y) break;
    39            double mi=1e20;
    40            for (int i=1; i<=m; i++)
    41              if (dcmp(a[i][y])>0&&(!x||mi>a[i][0]/a[i][y])) {x=i; mi=a[i][0]/a[i][y];}
    42            if (!x) break;
    43            pivot(x,y);
    44     }
    45 }
    46 
    47 int main()
    48 {
    49     scanf("%d%d",&m,&n);
    50     for (int i=1; i<=m; i++) scanf("%lf",&a[i][0]);
    51     for (int i=1; i<=n; i++)
    52     {
    53         int l,r,d;
    54         scanf("%d%d%d",&l,&r,&d);
    55         for (int j=l; j<=r; j++) a[j][i]=1;
    56         a[0][i]=d;
    57     }
    58     simplex();
    59     printf("%d
    ",(int)a[0][0]);
    60     return 0;
    61 }
    3112
  • 相关阅读:
    June. 26th 2018, Week 26th. Tuesday
    June. 25th 2018, Week 26th. Monday
    June. 24th 2018, Week 26th. Sunday
    June. 23rd 2018, Week 25th. Saturday
    June. 22 2018, Week 25th. Friday
    June. 21 2018, Week 25th. Thursday
    June. 20 2018, Week 25th. Wednesday
    【2018.10.11 C与C++基础】C Preprocessor的功能及缺陷(草稿)
    June.19 2018, Week 25th Tuesday
    June 18. 2018, Week 25th. Monday
  • 原文地址:https://www.cnblogs.com/phile/p/5658603.html
Copyright © 2011-2022 走看看