「Usaco2005 Dec」清理牛棚(spfa秒杀线段树dp)

约翰的奶牛们从小娇生惯养,她们无法容忍牛棚里的任何脏东西. 
约翰发现,如果要使这群有洁癖的奶牛满意,他不得不雇佣她们中的一些来清扫牛棚, 约翰的奶牛中有N(1≤N≤10000)头愿意通过清扫牛棚来挣一些零花钱. 
由于在某个时段中奶牛们会在牛棚里随时随地地乱扔垃圾,自然地,她们要求在这段时间里,无论什么时候至少要有一头奶牛正在打扫. 
需要打扫的时段从某一天的第M秒开始,到第E秒结束f0≤M≤E≤86399).注意这里的秒是指时间段而不是时间点,也就是说,每天需要打扫的总时间是E-M+I秒.  
约翰已经从每头牛那里得到了她们愿意接受的工作计划:对于某一头牛,她每天都愿意在笫T1...T2秒的时间段内工作 (where M <= T1 <= T2 <= E),所要求的报酬是S美元(0≤S≤500000).与需打扫时段的描述一样,如果一头奶牛愿意工作的时段是每天的第10_20秒,那她总共工作的时间是11秒,而不是10秒.约翰一旦决定雇佣某一头奶牛,就必须付给她全额的工资,而不能只让她工作一段时间,然后再按这段时间在她愿意工作的总时间中所占的百分比来决定她的工资.现在请你帮约翰决定该雇佣哪些奶牛以保持牛棚的清洁,当然,在能让奶牛们满意的前提下,约翰希望使总花费尽量小。 

输入

第1行:3个正整数N,M,E,用空格隔开.  
第2到N+1行:第i+l行给出了编号为i的奶牛的工作计划,即3个用空格隔开的正整数Ti,T2,S。 

输出

输出一个整数,表示约翰需要为牛棚清理工作支付的最少费用.如果清理工作不可能完成,那么输出-1

样例输入 Copy

3 0 4
0 2 3
3 4 2
0 0 1

样例输出 Copy

5

额.....第一感觉dp吧,方程式也比较好推,有点类似背包,

按左端点排序后

f[i]表示取第i个的最小费用

f[i]=min(f[j])+w[i] 当j的结束时间>=i的开始时间-1

答案就是所有的i满足i的结束时间>=结束时间-1

果断O(n^2)(哇塞百度上全都是线段树优化dp的嘢)

讲讲我的思路:

首先,化简题目:每一只牛对应一个覆盖的区间,可以重复,每一只牛有一个花费,求覆盖全区间的最小值。

把每个牛的起始,终止时间抽象成点,区间覆盖问题。

于是我该怎么处理往之前的点跑呢?

于是在旁边大佬的协助之下,我们想到了最短路这个东西。

在起点和终点之间连一条权值为代价的边 ,在第i个时间点和第i-1个时间点之间连一条0边,然后直接跑spfa

个人认为这个思路还是非常巧妙的

于是代码就没有什么含金量了,裸的spfa即可

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct edge
{
    int dis,to,next;
}e[maxn];
int n,m,E;
int head[maxn],cnt;
inline int addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[from]=cnt;
}
int vis[maxn],dis[maxn];
queue < int > q;
void spfa()
{
    for(int i=m;i<=E;i++)
    {
        dis[i]=0x7fffffff;
        vis[i]=0;
    }
    q.push(m);
    vis[m]=1;
    dis[m]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].dis)
            {
                dis[v]=dis[u]+e[i].dis;
                if(vis[v]==0)
                {
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&E);
    E++;
    for(int i=1;i<=n;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y+1,z);
    }
    for(int i=m;i<=E-1;i++)
    {
        addedge(i,i-1,0);
    }
    spfa();
    if(dis[E]==0x7fffffff)
    {
        printf("-1");
        return 0;
    }
    printf("%d ",dis[E]);
    return 0;
}

(完)

posted @ 2019-08-13 23:23  阿基米德的澡盆  阅读(222)  评论(0编辑  收藏  举报