poj/pku 3680(最小费用最大流)

来源:互联网 发布:程序员怎么学 编辑:程序博客网 时间:2024/05/21 10:10

题目链接: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,如果求最小费用则费用这里取反,否则为正!假设我们求最大费用最大流,我们每次都找源点到汇点的费用最长路,且每次找出一条路径都会将其经过的区间覆盖一次,如果不存在增广路则意味着不能在继续选区间啦!


代码:

#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[N],e;int src,sin;struct node1{    int x, y,c;}a[N/2];int b[N];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[N],que[N],pre[N];int Cost,Flow;bool isque[N];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;}



原创粉丝点击