您的位置:首页 > 其它

【codevs 1618】[省队选拔赛浙江]防守战线(单纯形)

2016-11-10 21:09 239 查看
1618 防守战线省队选拔赛浙江
 时间限制: 2 s 空间限制: 256000 KB  题目等级 : 大师 Master
题目描述 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。

 

【单纯形裸题】 
【单纯形是解决线性规划问题最大化的一种算法。线性规划问题的解决,一般首先要根据题意列出求解最大值的多项式,并列出符合题意的不等式组,并通过加减特定的值(用未知量表示)转变为等式,另外加上使之成为等式的点组成的集合叫做基变量集合,原题中包含的位置点组成的集合叫非基变量集合】

 【线性规划分为标准型和松弛型,简单的来说,标准型就是由不等式表示的,松弛型就是由等式表示的,就此可知松弛型和标准型是可以互相转换的,因为等式相对来说比较好处理,所以一般来说都化为松弛型来处理】

   


【在做单纯形的时候,先假定基本解是一组可行解,可以得知当一个变量的非负系数增大时,也会使总体的值增大,所以要尽可能的增大每个变量的非负系数,以达到求最大值的目的。直到所有的变量的系数都小于0了,就结束。当然每个数都不能无限增大——它是有限制的,所以最多只能增大到最紧的限制,如果最紧限制为0,则返回极大值,即当前的求解的多项式无上限,可以无限增大

】 
 【增大变量的系数,通过转轴操作来实现,转轴其实就是一个基变量与非基变量的替换,所谓替换,其实只是用这个式子中的其他变量来表示当前变量并将它的系数化为一,并代入其他等式中(包括求max的多项式),每次选择的非基变量都必须是满足限制的编号最小的一个,这样可以避免被一些特殊数据卡掉】

附上转轴的代码:


 

 

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define EPS 1e-7
#define INF 1e10
using namespace std;
int n,m;
double A[1010][10100],b[10010],c[10010];//a数组存花费;A[i][j]存在第j个不等关系所化的等式中xi是否出现过;b数组存每个不等关系所化的等式中的常数项;c数组存最小花费的式子中x[i]的系数
double ans,v;
inline void pivot(int l,int e)
{
int i,j;
b[l]/=A[l][e];
for (i=1;i<=m;++i)
if (i!=e) A[l][i]/=A[l][e];
A[l][e]=1/A[l][e];
for (i=1;i<=n;++i)
if (i!=l&&fabs(A[i][e])>EPS)
{
b[i]-=A[i][e]*b[l];//用替代的式子更改每一个等式,此处是在更改常数项的值
for (j=1;j<=m;++j)
if (j!=e) A[i][j]-=A[i][e]*A[l][j];
A[i][e]=-A[i][e]*A[l][e];
}
v+=c[e]*b[l];
for (i=1;i<=m;++i)
if (i!=e) c[i]-=c[e]*A[l][i];
c[e]=-c[e]*A[l][e];
return;
}
inline double do1()
{
int i,l,e;
while (1)
{
for (i=1;i<=m;++i)
if (c[i]>EPS) break;
if ((e=i)==m+1)  return v;
double tmp=INF;
for (i=1;i<=n;++i)
if (A[i][e]>EPS&&b[i]/A[i][e]<tmp)
{tmp=b[i]/A[i][e]; l=i;}
if (tmp==INF) return INF;
pivot(l,e);
}

}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i)
scanf("%lf",&b[i]);
for (i=1;i<=m;++i)
{
int l,r,val;
scanf("%d%d%d",&l,&r,&val);
for (j=l;j<=r;++j)
A[j][i]=1;
c[i]=val;
}
ans=do1();
cout<<(long long)(ans+0.5)<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codevs 数学相关