poj/pku 3680(最小费用最大流)
2011-09-23 10:51
344 查看
题目链接:http://poj.org/problem?id=3680
题意描述:给你n(n<=200)个区间,每个区间有一个权值,且每个区间的实数点最多只能访问k次,现在让你选择区间使得所选权值和最大
分析:该题是最大费用最大流,k可以看成是容量限制,刚开始这样想,将给出的每个区间看成一个点,然后将区间(i,i+1)i从0一直取到最大看成一些点,那么源点连接每个给出区间点,自己创造的区间点连接汇点,每个区间点都对应一些自己创造的区间点,但是这样做,不能正确的确定边的容量和费用,所以这样是解不出来的,无赖只好百度了一下,网上的建图方法经典至极啊,是将区间看成一条边而我只停留在将区间看成点的程度上,将区间看成边,那么对于这样的区间(i,i+1)那么他们最多允许流过k次,费用设为0,那么对给出区间的区间,这样的边就可以流过的流量设为1,表示只能选择一次,费用自然是区间的权值,现在这里给出建图的方法:建图之前可以将区间点离散化一下,这样可以减少些点,使得点最多不超过402个,那么我们建立源点和汇点,源点连接第一个点容量为k,费用为0,最后一个点连接汇点费用为0,容量为k,之间相邻的点相连,费用为0,容量为k,此处建图就体现了区间中所有的点最多只能流过k次,即最多只能被覆盖k次,之后对于给出的区间,我们连接区间的两个端点,容量为1,如果求最小费用则费用这里取反,否则为正!假设我们求最大费用最大流,我们每次都找源点到汇点的费用最长路,且每次找出一条路径都会将其经过的区间覆盖一次,如果不存在增广路则意味着不能在继续选区间啦!
代码:
题意描述:给你n(n<=200)个区间,每个区间有一个权值,且每个区间的实数点最多只能访问k次,现在让你选择区间使得所选权值和最大
分析:该题是最大费用最大流,k可以看成是容量限制,刚开始这样想,将给出的每个区间看成一个点,然后将区间(i,i+1)i从0一直取到最大看成一些点,那么源点连接每个给出区间点,自己创造的区间点连接汇点,每个区间点都对应一些自己创造的区间点,但是这样做,不能正确的确定边的容量和费用,所以这样是解不出来的,无赖只好百度了一下,网上的建图方法经典至极啊,是将区间看成一条边而我只停留在将区间看成点的程度上,将区间看成边,那么对于这样的区间(i,i+1)那么他们最多允许流过k次,费用设为0,那么对给出区间的区间,这样的边就可以流过的流量设为1,表示只能选择一次,费用自然是区间的权值,现在这里给出建图的方法:建图之前可以将区间点离散化一下,这样可以减少些点,使得点最多不超过402个,那么我们建立源点和汇点,源点连接第一个点容量为k,费用为0,最后一个点连接汇点费用为0,容量为k,之间相邻的点相连,费用为0,容量为k,此处建图就体现了区间中所有的点最多只能流过k次,即最多只能被覆盖k次,之后对于给出的区间,我们连接区间的两个端点,容量为1,如果求最小费用则费用这里取反,否则为正!假设我们求最大费用最大流,我们每次都找源点到汇点的费用最长路,且每次找出一条路径都会将其经过的区间覆盖一次,如果不存在增广路则意味着不能在继续选区间啦!
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N=410; const int E=20000; const int inf=0x3fffffff; struct node { int x, y,nxt,c,w; }edge[E]; int head ,e; int src,sin; struct node1 { int x, y,c; }a[N/2]; int b ; void addedge(int x,int y, int w, int c) { edge[e].x=x; edge[e].y=y; edge[e].w=w; edge[e].c=c; edge[e].nxt=head[x]; head[x]=e++; edge[e].x=y; edge[e].y=x; edge[e].w=0; edge[e].c=-c; edge[e].nxt=head[y]; head[y]=e++; } int find(int x,int high) { int low=1; while(low<=high) { int mid=(low+high)>>1; if(b[mid]==x) return mid; if(b[mid]<x) low=mid+1; else high=mid-1; } } int dis ,que ,pre ; int Cost,Flow; bool isque ; void mincmaxf() { Cost=0;Flow=0;int u,v,i; while(1) { int f=0,r=1; for(i=src;i<=sin;i++) { dis[i]=inf; isque[i]=false; } dis[src]=0; que[0]=src; isque[src]=true; while(f!=r) { u=que[f]; f=(f+1)%N; for(i=head[u];i!=-1;i=edge[i].nxt) { v=edge[i].y; if(dis[v]>dis[u]+edge[i].c&&edge[i].w) { dis[v]=dis[u]+edge[i].c; pre[v]=i; if(!isque[v]) { que[r]=v; r=(r+1)%N; isque[v]=true; } } } isque[u]=false; } if(dis[sin]==inf)break; int p,min=inf; for(u=sin;u!=src;u=edge[pre[u]].x) { p=pre[u]; if(min>edge[p].w) min=edge[p].w; } Flow+=min; Cost+=min*dis[sin]; for(u=sin;u!=src;u=edge[pre[u]].x) { p=pre[u]; edge[p].w-=min; edge[p^1].w+=min; } } } int main () { int t,n,k,i,j,x,y,c; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&k); memset(head,-1,sizeof(head)); e=0; for(i=1;i<=n;i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c); b[i*2-1]=a[i].x; b[i*2]=a[i].y; } sort(b+1,b+2*n+1); for(i=2,j=2;i<=2*n;i++) if(b[i]!=b[i-1]) b[j++]=b[i]; sin=j;src=0; for(i=0;i<j;i++) addedge(i,i+1,k,0); for(i=1;i<=n;i++) { x=find(a[i].x,j-1); y=find(a[i].y,j-1); if(x>y)swap(x,y); addedge(x,y,1,-a[i].c); } mincmaxf(); printf("%d\n",-Cost); } return 0; }
相关文章推荐
- poj 3680(最小费用最大流)
- POJ3680 Intervals(最小费用最大流)
- POJ 3680 Intervals (最小费用最大流+离散化)
- POJ 3680 最小费用最大流
- poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙
- POJ 3680 <离散化+最小费用最大流模版>
- POJ 3680 最小费用最大流
- Intervals (poj 3680 离散化+最小费用最大流)
- poj 3680(最小费用最大流)
- POJ 3680: Intervals【最小费用最大流】
- POJ 3680 最小费用最大流
- POJ 3680 最小费用最大流
- POJ 3680 最小费用最大流
- poj 3680 Intervals【最小费用最大流】
- POJ 3422 Kaka's Matrix Travels(最小费用最大流)
- POJ 2315 最小费用最大流
- poj 2135 Farm Tour (最小费用最大流)
- POJ-3680-Intervals
- hdu 1533 && pku 2195 最小费用最大流
- poj 2135 Farm Tour--最小费用最大流--邻接表--构图的时候注意退边--以及退边的算法