【BZOJ3112】防守战线(ZJOI2013)-单纯形法+对偶理论

测试地址(题面在Discuss里):防守战线
做法:这题需要用到线性规划知识中的单纯形法和对偶理论。
观察题目,设每个位置建的塔数为xi,我们可以知道所有约束条件都可以表示成Rii=LixiDi的形式,我们把系数矩阵记作A,所有变量xi排成一个列向量X,那么这个线性规划可以写成:
目标函数:minCX,约束条件:AXB,X0
根据对偶理论,可以将问题转化成关于Y的对偶问题:
目标函数:maxBTY,约束条件:ATYCT,Y0
这样的话,两个问题的最优解是相等的,且能保证目标函数取最优解时各个变量为整数,所以我们只需用单纯形法解后面的问题即可。
以下是本人代码(TLE70分代码,更高超的卡常数技巧有待学习):

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define inf 1e9
#define eps 1e-8
using namespace std;
int n,m,p[10010];
double a[1010][10010]={0},tmp[10010];

void solve()
{
  while(1)
  {
    int k1,k2;
    double Max;
    memset(tmp,0,sizeof(tmp));
    memset(p,0,sizeof(p));

    for(int i=1;i<=m;i++)
      if (a[n+1][i]<0)
      {
        double Min=inf;
        for(int j=1;j<=n;j++)
          if (a[j][i]>0)
          {
            double t=a[j][m+1]/a[j][i];
            if (Min>t)
            {
              Min=t;
              p[i]=j;
            }
          }
        if (p[i]) tmp[i]=-a[p[i]][m+1]*a[n+1][i]/a[p[i]][i];
      }

    Max=0.0;
    for(int i=1;i<=m;i++)
      if (Max<tmp[i])
      {
        Max=tmp[i];
        k2=i;
      }
    if (fabs(Max)<eps) break;
    k1=p[k2];

    a[k1][k2]=1.0/a[k1][k2];
    for(int i=1;i<=m+1;i++)
      if (i!=k2) a[k1][i]*=a[k1][k2];
    for(int i=1;i<=n+1;i++)
      if (i!=k1)
      {
        for(int j=1;j<=m+1;j++)
          if (j!=k2) a[i][j]-=a[i][k2]*a[k1][j];
      }
    for(int i=1;i<=n+1;i++)
      if (i!=k1) a[i][k2]=-a[i][k2]*a[k1][k2];
  }
}

int main()
{
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++)
    scanf("%lf",&a[i][m+1]);
  for(int i=1;i<=m;i++)
  {
    int l,r;
    double d;
    scanf("%d%d%lf",&l,&r,&d);
    for(int j=l;j<=r;j++)
      a[j][i]=1;
    a[n+1][i]=-d;
  }
  solve();
  printf("%.0lf",a[n+1][m+1]);

  return 0;
}
posted @ 2017-06-14 17:23  Maxwei_wzj  阅读(123)  评论(0编辑  收藏  举报