POJ 3680 Intervals
2010-12-04 09:30
218 查看
如果不是看到分类用最小费用流来做,我自己肯定想不到。。。
一开始想的构图是每个区间作为一个顶点,源点向每个区间连一条容量为1的边,然后找一些集合,每个集合代表一段区间,对于所有在这个区间内相交错的区间,向该集合代表的顶点连一条容量为1的边,然后每个集合顶点向汇点连一条容量为k的边
但问题是那些区间集合没有什么好的方法可以确定,看了网上别人的思路,很巧妙
先将区间离散化,将左右端点号从小到大排序,去掉重复的,然后每个端点对应一个点,第i个端点向第i+1个端点连一条容量为k的边
源点向第一个顶点连容量为k的边,最后一个端点向汇点连一条容量为k的边,费用都为0,然后对于每个区间,找到他们左右端点在图中的顶点好,从小的向大的连一条容量为1,费用为该区间权值的边
实际上当流到达一个顶点的时候,可以选择分配是否分配流,由于顶点已排序,大区间正好覆盖小区间,边上的容量限制也符合了题目中每个点覆盖的次数(转化为所在区间)
然后跑一次最大费用最大流即可
代码:
一开始想的构图是每个区间作为一个顶点,源点向每个区间连一条容量为1的边,然后找一些集合,每个集合代表一段区间,对于所有在这个区间内相交错的区间,向该集合代表的顶点连一条容量为1的边,然后每个集合顶点向汇点连一条容量为k的边
但问题是那些区间集合没有什么好的方法可以确定,看了网上别人的思路,很巧妙
先将区间离散化,将左右端点号从小到大排序,去掉重复的,然后每个端点对应一个点,第i个端点向第i+1个端点连一条容量为k的边
源点向第一个顶点连容量为k的边,最后一个端点向汇点连一条容量为k的边,费用都为0,然后对于每个区间,找到他们左右端点在图中的顶点好,从小的向大的连一条容量为1,费用为该区间权值的边
实际上当流到达一个顶点的时候,可以选择分配是否分配流,由于顶点已排序,大区间正好覆盖小区间,边上的容量限制也符合了题目中每个点覆盖的次数(转化为所在区间)
然后跑一次最大费用最大流即可
代码:
#include<iostream> #include<algorithm> #include<queue> using namespace std; #define MAX 405 const int inf=1<<29; struct edge { int u,v,c,f,b,next; }g[200000]; struct node { int l,r,cost; }interval[MAX]; int adj[MAX],dis[MAX],pre[MAX],r[MAX]; bool vis[MAX]; int s,t,n,k,vn,ans,e,cnt; void add(int u,int v,int c,int b) { g[e].u=u; g[e].v=v; g[e].c=c; g[e].f=0; g[e].b=b; g[e].next=adj[u]; adj[u]=e++; g[e].u=v; g[e].v=u; g[e].c=0; g[e].f=0; g[e].b=-b; g[e].next=adj[v]; adj[v]=e++; } int find(int x) { int low=1,high=cnt,mid; while(low<high) { mid=(low+high)/2; if(r[mid]<x) low=mid+1; else high=mid; } return low; } void build() { int i,j,a,b; memset(adj,-1,sizeof(adj)); e=0; s=0; t=cnt+1; for(i=1;i<=cnt;i++) { add(i,i+1,k,0); } add(s,1,k,0); add(cnt,t,k,0); for(i=1;i<=n;i++) { a=find(interval[i].l); b=find(interval[i].r); add(a,b,1,interval[i].cost); } } void spfa() { int i,j,cur; memset(vis,0,sizeof(vis)); queue<int>q; q.push(s); vis[s]=true; while(!q.empty()) { i=q.front(); q.pop(); vis[i]=false; for(cur=adj[i];cur!=-1;cur=g[cur].next) { j=g[cur].v; if(g[cur].c>g[cur].f&&dis[j]<dis[i]+g[cur].b) { dis[j]=dis[i]+g[cur].b; pre[j]=cur; if(!vis[j]) { vis[j]=true; q.push(j); } } } } } void solve() { int i,j,minf; ans=0; while(true) { memset(dis,-1,sizeof(dis)); memset(pre,-1,sizeof(pre)); dis[s]=0; spfa(); if(dis[t]==-1) break; minf=inf; for(i=pre[t];i!=-1;i=pre[g[i].u]) { minf=min(minf,g[i].c-g[i].f); } for(i=pre[t];i!=-1;i=pre[g[i].u]) { g[i].f+=minf; g[i^1].f-=minf; } ans+=minf*dis[t]; } printf("%d/n",ans); } int main() { int i,j,test; scanf("%d",&test); while(test--) { j=0; scanf("%d %d",&n,&k); for(i=1;i<=n;i++) { scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].cost); r[++j]=interval[i].l; r[++j]=interval[i].r; } sort(r+1,r+j+1); cnt=0; for(i=1;i<=j;i++) { if(cnt==0||r[cnt]!=r[i]) r[++cnt]=r[i]; } build(); solve(); } return 0; }
相关文章推荐
- poj 3680 Intervals 【坐标区间离散化 + 最大费用最大流】
- poj 3680 Intervals(费用流)
- poj 3680 Intervals 费用流
- POJ 3680_Intervals
- POJ3680——Intervals(费用流)
- POJ 3680 Intervals (最大费用最大流)
- POJ 3680_Intervals
- poj 3680 Intervals
- POJ 3680 Intervals(最小费用流)
- POJ 3680 Intervals (费用流经典构图题)
- POJ-3680-Intervals
- 【POJ】【3680】Intervals
- POJ 3680 Intervals 区间k覆盖 费用流
- poj 3680 Intervals(巧妙构图,费用流)
- 【网络流】 POJ 3680 Intervals
- POJ 3680 Intervals(离散化+费用流)
- poj 3680 Intervals 最大费用流
- [费用流] POJ 3680 Intervals
- POJ-3680:Intervals (费用流)
- POJ 3680 Intervals(区间k覆盖问题)