Luogu6967 [NEERC2016]Delight for a Cat

Luogu6967 [NEERC2016]Delight for a Cat

单纯形法

太弱了,不会网络流,只好用单纯形法辗过去。

很容易发现,这是一个线性规划问题,我们可以设\(n\)个变量\(x_1,x_2,\cdots,x_n\)表示每个时刻猫的状态,\(x_i=0\)表示猫在\(i\)时刻进食,\(x_i=1\)表示猫在\(i\)时刻睡觉。

我们可以列出以下这些方程:

\[\begin{cases} 0 \le x_1 \le 1 \\ 0 \le x_2 \le 1 \\ \cdots\\ 0 \le x_n \le 1 \\ \sum_{i=1}^k x_i \ge ms \\ k-\sum_{i=1}^k x_i \ge me\\ \cdots\\ \sum_{i=n-k+1}^n x_i \ge ms \\ k-\sum_{i=n-k+1}^n x_i \ge me\\ \end{cases} \]

求:

\[\max \sum_{i=1}^n s_i x_i + e_i (1-x_i) \]

根据线性规划整数最优解的判定条件,可以证明整数解一定是本题中线性规划的最优解(伪证:因为本题可以费用流,所以单纯形法能够跑出整数解)。

把方程经过添加负号等变换,转化为标准形式,然后直接跑单纯形法。

提交一下,发现\(TLE\)了。

实际上,我们这里的单纯形法需要初始化,因为一开始的全\(0\)解是不合法的,这会消耗大量时间,引用一句话:

需要注意的一点是,大部分的OI试题得出的限制条件都有一定的性质,而执行初始化操作会破坏这些性质,造成运行时间的无谓增加。 ——董克凡《浅谈线性规划与对偶问题》

因此我们可以考虑手动初始化,也就是找到一组合法解,实际上这很容易构造,我们让\(me\)\(E\),\(k-me\)\(S\)不断循环得到一个长度为\(n\)的序列,容易发现,任意一个长度为\(k\)的子区间都含有\(me\)\(E\)\(k-me\)\(S\),显然合法。

我们把这个序列作为标准序列,把\(x_i\)重新定义,即\(x_i=0\)表示\(i\)时刻状态与标准序列中\(i\)时刻状态不同,\(x_i=1\)表示\(i\)时刻状态与标准序列中\(i\)时刻状态相同。

然后再跑单纯形法就可以通过本题了。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define db double
using namespace std;
const db eps=1e-7;
int n,m,k,ms,me,s[1005],e[1005],id[4005];
db z,ans[4005],a[3005][1005];
bool r[1005];
void pivot(int l,int e)
{
    swap(id[n+l],id[e]);
    db t(a[l][e]);
    a[l][e]=1.0;
    for (int i=0;i<=n;++i)
        a[l][i]/=t;
    for (int i=0;i<=m;++i)
        if (i!=l && fabs(a[i][e])>eps)
        {
            db t(a[i][e]);
            a[i][e]=0.0;
            for (int j=0;j<=n;++j)
                a[i][j]-=t*a[l][j];
        }
}
void simplex()
{
    for (;;)
    {
        int e(0),l(0);
        db mx(eps);
        for (int i=1;i<=n;++i)
            if (a[0][i]>mx)
                mx=a[0][i],e=i;
        if (!e)
            return;
        db mn(1e18);
        for (int i=1;i<=m;++i)
            if (a[i][e]>eps && a[i][0]/a[i][e]<mn)
                mn=a[i][0]/a[i][e],l=i;
        pivot(l,e);
    }
}
int main()
{
    scanf("%d%d%d%d",&n,&k,&ms,&me);
    for (int i=1;i<=n;++i)
        scanf("%d",&s[i]);
    for (int i=1;i<=n;++i)
        scanf("%d",&e[i]);
    for (int i=1;i<=n;++i)
    {
        r[i]=((i-1)%k+1>me);
        if (r[i])
            z+=s[i],a[0][i]=e[i]-s[i]; else
            z+=e[i],a[0][i]=s[i]-e[i];
        a[i][0]=1.0,a[i][i]=1.0;
    }
    m=n;
    for (int i=1;i<=n-k+1;++i)
    {
        ++m,a[m][0]=-ms;
        for (int j=i;j<i+k;++j)
            a[m][j]=-1.0;
        ++m,a[m][0]=k-me;
        for (int j=i;j<i+k;++j)
            a[m][j]=1.0;
    }
    for (int i=1;i<=n;++i)
        if (r[i])
            for (int j=n+1;j<=m;++j)
                a[j][0]-=a[j][i],a[j][i]=-a[j][i];
    for (int i=1;i<=n;++i)
        id[i]=i;
    simplex();
    for (int i=1;i<=m;++i)
        ans[id[n+i]]=a[i][0];
    printf("%.lf\n",z-a[0][0]);
    for (int i=1;i<=n;++i)
        putchar(((fabs(ans[i])>eps) ^ r[i])?'S':'E');
    putchar('\n');
    return 0;
}
posted @ 2021-04-26 11:40  GK0328  阅读(75)  评论(0编辑  收藏  举报