[bzoj3550][单纯形][线性规划][ONTAK2010]Vacation

3 篇文章 0 订阅
3 篇文章 0 订阅

3550: [ONTAK2010]Vacation

Time Limit: 10 Sec Memory Limit: 96 MB
Submit: 310 Solved: 222
[Submit][Status][Discuss]
Description

有3N个数,你需要选出一些数,首先保证任意长度为N的区间中选出的数的个数<=K个,其次要保证选出的数的个数最大。

Input

第一行两个整数N,K。
第二行有3N个整数。

Output

一行一个整数表示答案。

Sample Input

5 3

14 21 9 30 11 8 1 20 29 23 17 27 7 8 35

Sample Output

195

HINT

【数据范围】

N<=200,K<=10。

Source

By Sbullet

sol:
单纯形,注意一下这里要限制每个点只能选一次。

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
int n,m,M;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
const int N=1110;
const double eps=1e-8;
int l,e;
double a[N][N],b[N],c[N];
double v;
inline void pivot()
{
    b[l]/=a[l][e];
    for(int i=1;i<=m;++i) if(i!=e) a[i][e]/=a[l][e];
    a[l][e]=1/a[l][e];
    for(int i=1;i<=M;++i)
    if(fabs(a[i][e])>eps&&i!=l)
    {
        b[i]-=b[l]*a[i][e];
        for(int j=1;j<=m;++j) if(j!=e) a[i][j]-=a[l][j]*a[i][e];
        a[i][e]*=-a[l][e]; 
    }
    v+=c[e]*b[l];
    for(int i=1;i<=m;++i)
    if(i!=e) c[i]-=c[e]*a[l][i];
    c[e]*=-a[l][e];
}
inline double simplex()
{
    while(true)
    {
        l=0;e=0;
        for(e=1;e<=m;++e) if(c[e]>eps) break;
        if(e==m+1) return v;
        double save=1e9;
        for(int i=1;i<=M;++i)
        if(a[i][e]>eps&&save>b[i]/a[i][e]) save=b[i]/a[i][e],l=i;
//      if(save==1e9) return 1e9;
        pivot();
    }
}
int main()
{
//  freopen("3550.in","r",stdin);
//  freopen(".out","w",stdout);
    n=read();
    m=n*3;
    int k=read();
    for(int i=1;i<=m;++i) c[i]=read();
    for(int i=n*2+1;i>=1;--i)
    {
        b[i]=k;
        for(int j=1;j<=n;++j)
        if(i+j-1>m) break;
        else a[i][i+j-1]=1;
    }
    M=n*2+1;
    for(int i=1;i<=m;++i)
    {
        ++M;
        b[M]=1;
        a[M][i]=1;
    }
    printf("%d",(int)(simplex()+0.5));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值