您的位置:首页 > 其它

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

2017-02-08 09:09 459 查看

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

By Claris

[b]民间解法:[/b]

//(贪心)按权值排序匈牙利
/**************************************************************
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
;
int n,ans,person,match
,times
;
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
;
int n,ans,S,T,num,dis
,id
,li
,ri
,ls
,rs
,prev
,flow
,q[N*2];
bool vis
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: