POJ 3680 Intervals

来源:互联网 发布:淘宝买射钉枪警察找我 编辑:程序博客网 时间:2024/06/06 01:55

题目在这里呀

哎失望地开始口糊题解了呀,bzoj2879 TLE调不出来,于是难过地开始整理AC的题了(ಥ﹏ಥ)...

这题很有想法的!

题意:有n个区间,每个区间有一个权值wi,从中取一些区间,使得任意整数点的被包含次数小于等于k,并且这些区间的权值和最大。

题解:这题和志愿者招募蜜汁相似啊ww~~

对于每个点列出式子。

设xi表示第i个区间有没有包含该点,xi=0 or 1

再引入一个余量ri

这样式子可以写成:

0+r0=k

x1+x3+x6+r1=k

x2+x5+x6+r2=k

......

0+rn+1=k


相邻两点相减,x2+x5+r2-x1-x3-r1=0

看见右端为0,可以想到一个点的入流=出流。

而相邻两个点相减多出来的一定是新产生的或者是新消失的。

那么就可以把问题转化成费用流啦!

区间的两个端点连边,流量为1,费用为-wi(否则不会去流)

相邻端点之间连边,流量为k,费用为0

建立源点和汇点与第一个和最后一个点连边。

跑费用流即可。

这题或许有点难理解(真的w

边数初始化1这个东西永远不能忘!!





#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <queue>#include <map>#define N 1010using namespace std;int Q,n,k,cnt,tot,S,T,ans,mark[N],dis[N],head[N],cur[N],c[N],a[N],b[N],w[N];map<int,int> id;const int inf=1e9;struct edge{int from,to,next,v,c;}e[N];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;}inline void add_edge(int x,int y,int v,int c){e[++cnt]=(edge){x,y,head[x],v,c};head[x]=cnt;e[++cnt]=(edge){y,x,head[y],0,-c};head[y]=cnt;}inline bool spfa(){memset(mark,0,sizeof(mark));for(int i=0;i<=T;i++) dis[i]=inf;queue<int>q;dis[S]=0;q.push(S);mark[S]=1;while(!q.empty()){int now=q.front();q.pop();for(int i=head[now];i!=-1;i=e[i].next){int v1=e[i].to;if(e[i].v && dis[v1]>dis[now]+e[i].c){dis[v1]=dis[now]+e[i].c;cur[v1]=i;if(!mark[v1]){q.push(v1);mark[v1]=1;}}}mark[now]=0;}return dis[T]!=inf;}inline void mcf(){ans=0;while(spfa()){int flow=inf;for(int i=cur[T];i;i=cur[e[i].from]) flow=min(flow,e[i].v);ans+=flow*dis[T];for(int i=cur[T];i;i=cur[e[i].from]){e[i].v-=flow;e[i ^ 1].v+=flow;}}}int main(){Q=read();while(Q--){memset(head,-1,sizeof(head));memset(cur,0,sizeof(cur));memset(c,0,sizeof(c));n=read();k=read();for(int i=1;i<=n;i++){a[i]=read();b[i]=read();w[i]=read();c[i+i-1]=a[i];c[i+i]=b[i];}sort(c+1,c+n+n+1);tot=0;cnt=1;for(int i=1;i<=n+n;i++) if(i==1 || c[i] != c[i-1]) id[c[i]]=++tot;S=0;T=tot+1;for(int i=1;i<tot;i++) add_edge(i,i+1,k,0);add_edge(S,1,k,0);add_edge(tot,T,k,0);for(int i=1;i<=n;i++) add_edge(id[a[i]],id[b[i]],1,-w[i]);mcf();printf("%d\n",-ans);}return 0;}


原创粉丝点击