bzoj 3112: [Zjoi2013]防守战线 (单纯形)

题目描述 Description

战线可以看作一个长度为 n 的序列,现在需要在这个序列上建塔来防守敌
兵,在序列第 i号位置上建一座塔有 Ci 的花费,且一个位置可以建任意多的塔
费用累加计算。有 m个区间[L1, R1], [L2, R2], …, [Lm, Rm],在第 i 个区间
的范围内要建至少 Di座塔。求最少花费。

输入描述 Input Description

第一行为两个数n,m。
接下来一行,有 n个数,描述 C数组。
接下来 m行,每行三个数 Li,Ri,Di,描述一个区间。

输出描述 Output Description

仅包含一行,一个数,为最少花费。

样例输入 Sample Input

5 3
1 5 6 3 4
2 3 1
1 5 4
3 5 2

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

位置 1建 2个塔,位置 3建一个塔,位置 4建一个塔。花费 1*2+6+3=11。

对于 20%的数据,n≤20,m≤20。
对于 50%的数据(包括上部分的数据),Di 全部为1。
对于 70%的数据(包括上部分的数据),n≤100,m≤1000。
对于 100%的数据,n≤1000,m≤10000,1≤Li≤Ri≤n,其余数据均≤10000。

 

题解:单纯形

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 1e10
#define eps 1e-7
using namespace std;
int n,m;
double a[1010][10100],b[1010],c[10100],v,ans;
void pivot(int l,int e)//l是替出变量,e是替入变量 
{
  b[l]/=a[l][e];
  for (int i=1;i<=n;i++)//改变限制最近的式子的系数 
   if (i!=e) a[l][i]/=a[l][e];
  a[l][e]=1/a[l][e];//相当于把导入变量与导出变量的系数互换,因为刚开始式子左边的系数为1,所以为原位置系数的倒数 
  for (int i=1;i<=m;i++)
   if ((i!=l)&&(fabs(a[i][e])>eps))//不是限制最近的式子,替入变量的系数不为0 
    {
      b[i]-=b[l]*a[i][e];//相当于把替入变量等于的式子带入含替入变量的式子,改变式子的值 
      for (int j=1;j<=n;j++)
       if (j!=e)  a[i][j]-=a[l][j]*a[i][e];
      a[i][e]=-a[l][e]*a[i][e];
    }
   v+=c[e]*b[l];//累计计算当前目标函数常数的值 
   for (int i=1;i<=n;i++)
    if (i!=e)  c[i]-=c[e]*a[l][i];
   c[e]=-c[e]*a[l][e];
}
double simplex()
{
  int i,l,e;
  double t;
  while (true)
   {
   	 for (i=1;i<=n;i++)
   	  if (c[i]>eps) break;
   	 e=i;
   	 if (e==n+1) return v;
   	 t=inf;
   	 for (i=1;i<=m;i++)
   	  if (a[i][e]>eps&&t>(b[i]/a[i][e]))
   	   t=b[i]/a[i][e],l=i;
   	 if (t==inf) return inf;
   	 pivot(l,e);
   	 //cout<<l<<" "<<e<<endl;
   	 //cout<<v<<endl;
   }
}
int main()
{
  scanf("%d%d",&m,&n);
  for (int i=1;i<=m;i++)
   scanf("%lf",&b[i]);
  for (int i=1;i<=n;i++)
   {
     int l,r,x;
     scanf("%d%d%lf",&l,&r,&c[i]);
     for (int j=l;j<=r;j++)
      a[j][i]++;
   }
  ans=simplex();
  printf("%.0lf",ans);
  return 0;
}






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值