4276: [ONTAK2015]Bajtman i Okrągły Robin

4276: [ONTAK2015]Bajtman i Okrągły Robin

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 345  Solved: 186
[Submit][Status][Discuss]

Description

有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元。作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢?
 

 

Input

第一行包含一个正整数n(1<=n<=5000),表示强盗的个数。
接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]<=10000),依次描述每一个强盗。
 

 

Output

输出一个整数,即可以挽回的损失的最大值。
 

 

Sample Input

4
1 4 40
2 4 10
2 3 30
1 3 20

Sample Output

90

HINT

 

Source

 

民间解法:

//(贪心)按权值排序匈牙利
/**************************************************************
    Problem: 4276
    User: gryz2016
    Language: C++
    Result: Accepted
    Time:16732 ms
    Memory:948 kb
****************************************************************/
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int N=5005;
struct node{int a,b,w;}f[N];
int n,ans,person,match[N],times[N];
inline bool cmp(const node &a,const node &b){
    return a.w>b.w; 
}
bool hunguary(int x){
    times[x]=person;
    for(int i=f[x].a;i<=f[x].b;i++){
        if(!match[i]||(times[match[i]]!=person&&hunguary(match[i]))){
            match[i]=x;
            return 1;
        }
    }
    return 0;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) f[i].a=read(),f[i].b=read()-1,f[i].w=read();
    sort(f+1,f+n+1,cmp);
    for(int i=1;i<=n;i++){
        person++;
        if(hunguary(i)) ans+=f[i].w;
    }
    printf("%d",ans);
    return 0;
}

官方解法: 

费用流作法是最暴力最显然的吧。。
  一眼建图题,跑最大费用流,所以裸的是水不过去的。。
  朴素建图:用xi表示每个强盗,用yi表示区间[i,i+1]。
    (S,xi,1,ci)
    (xi,yi(ai<=yi<bi),1,0)
    (yi,T,1,0)
  然后这样是过不了的。

  我们发现每次连边都是左边一个点对应右边一段连续的区间,所以可以用线段树来优化。
在原来的基础上,我们不再从xi向每个对应的yi连边,而用线段树中的点来表示区间[ai,bi),然后连边。

对于线段树中的点,由父亲向儿子连容量为inf,费用为0的边。

由叶子节点向汇点T连容量为1,费用为0的边。

然后跑费用流。(引自ws_fqk

/**************************************************************
    Problem: 4276
    User: gryz2016
    Language: C++
    Result: Accepted
    Time:31629 ms
    Memory:5736 kb
****************************************************************/
#include<cstdio>
#include<iostream>
#define lc k<<1
#define rc k<<1|1
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int N=30005;
const int M=2e5+5;
const int inf=~0u>>2;
struct node{int v,cap,cost,next;}e[M];int tot=1,head[N];
int n,ans,S,T,num,dis[N],id[N],li[N],ri[N],ls[N],rs[N],prev[N],flow[N],q[N*2];
bool vis[N];
void add(int x,int y,int z,int cost){
    e[++tot].v=y;e[tot].cap=z;e[tot].cost=cost;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].cap=0;e[tot].cost=-cost;e[tot].next=head[y];head[y]=tot;
}
void build(int k,int l,int r){
    id[k]=++num;
    if((li[k]=l)==(ri[k]=r)){
        add(id[k],T,1,0);
        return ;
    }
    int mid=l+r>>1;
    build(ls[k]=lc,l,mid);
    build(rs[k]=rc,mid+1,r);
    add(id[k],id[ls[k]],inf,0);
    add(id[k],id[rs[k]],inf,0);
}
void insert(int k,int opl,int opr,int now){
    if(li[k]==opl&&ri[k]==opr){
        add(now,id[k],1,0);
        return ;
    }
    int mid=li[k]+ri[k]>>1;
    if(opr<=mid) insert(ls[k],opl,opr,now);
    else if(opl>mid) insert(rs[k],opl,opr,now);
    else insert(ls[k],opl,mid,now),insert(rs[k],mid+1,opr,now);
}
bool spfa(){
    for(int i=S;i<=T;i++) vis[i]=0,dis[i]=-1;
    int h=0,t=1;q[t]=S;dis[S]=0;flow[S]=inf;
    while(h!=t){
        int x=q[++h];vis[x]=0;
        for(int i=head[x];i;i=e[i].next){
            if(e[i].cap&&dis[e[i].v]<dis[x]+e[i].cost){
                dis[e[i].v]=dis[x]+e[i].cost;
                prev[e[i].v]=i;
                flow[e[i].v]=min(flow[x],e[i].cap);
                if(!vis[e[i].v]){
                    vis[e[i].v]=1;
                    if(dis[e[i].v]>dis[x]) 
                        q[h--]=e[i].v;
                    else 
                        q[++t]=e[i].v;
                }
            }
        }
    }
    return dis[T]!=-1;
}
void augment(){
    for(int i=T;i!=S;i=e[prev[i]^1].v){
        e[prev[i]].cap-=flow[T];
        e[prev[i]^1].cap+=flow[T];
    }
    ans+=dis[T]*flow[T];
}
int main(){
    n=read();S=0;T=30000;
    build(1,1,5000);
    for(int i=1,a,b,c;i<=n;i++){
        a=read();b=read()-1;c=read();
        add(S,++num,1,c);
        insert(1,a,b,num);
    }
    while(spfa()) augment();
    printf("%d",ans);
    return 0;
}

 

posted @ 2017-02-08 09:09  神犇(shenben)  阅读(329)  评论(0编辑  收藏  举报