题目描述
战线可以看作一个长度为n 的序列,现在需要在这个序列上建塔来防守敌兵,在序列第i 号位置上建一座塔有Ci 的花费,且一个位置可以建任意多的塔,费用累加计算。有m 个区间[L1, R1], [L2, R2], …, [Lm, Rm],在第i 个区间的范围内要建至少Di 座塔。求最少花费。
输入输出格式
输入格式:
第一行为两个数n, m。
接下来一行,有n 个数,描述C 数组。
接下来m 行,每行三个数Li,Ri,Di,描述一个区间。
输出格式:
仅包含一行,一个数,为最少花费。
输入输出样例
输入样例#1:
5 3
1 5 6 3 4
2 3 1
1 5 4
3 5 2
输出样例#1:
11
说明
【样例说明】
位置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。
分析:
显然对于每一个区间都可以写出一个约束,
x
l
+
x
l
+
1
+
.
.
.
+
x
r
>
=
d
i
x_{l}+x_{l+1}+...+x_r>=d_i
xl+xl+1+...+xr>=di
要最小化
∑
i
=
1
n
c
i
∗
x
i
\sum_{i=1}^{n}c_i*x_i
∑i=1nci∗xi。
我们可以化成对偶线性规划。
需要把系数矩阵颠倒,即
A
′
[
j
]
[
i
]
=
A
[
i
]
[
j
]
A'[j][i]=A[i][j]
A′[j][i]=A[i][j]。
然后约束全部反号,不等式右边变为
c
i
c_i
ci。
然后最大化
∑
i
=
1
n
b
i
∗
x
i
\sum_{i=1}^{n}b_i*x_i
∑i=1nbi∗xi。
然后就是标准形式,直接单纯形即可。
代码:
#include<iostream>
#include<cstdio>
#include <cmath>
#include<algorithm>
const int maxn=1e3+7;
const int maxm=1e4+7;
const int inf=0x3f3f3f3f;
using namespace std;
int n,m;
int a[maxn][maxm],next[maxm];
void pivot(int l,int e)
{
for (int i=0;i<=n;i++)
{
if ((!a[i][e]) || (i==l)) continue;
for (int j=0;j<=m;j++)
{
if ((!a[l][j]) || (j==e)) continue;
a[i][j]-=a[i][e]*a[l][j];
}
a[i][e]=-a[i][e];
}
}
int simplex()
{
while (1)
{
int now=0;
for (int i=1;i<=m;i++)
{
if (a[0][i]>0)
{
now=i;
break;
}
}
if (now==0) return -a[0][0];
int tmp,minn=inf;
for (int i=1;i<=n;i++)
{
if ((a[i][now]>0) && (a[i][0]<minn))
{
tmp=i;
minn=a[i][0];
}
}
pivot(tmp,now);
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i][0]);
int x,y;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&a[0][i]);
for (int j=x;j<=y;j++) a[j][i]=1;
}
int ans=simplex();
printf("%d\n",ans);
}