poj 3680 Intervals(构图+最大费用最大流)

大致题意:

给你n个开区间,每个区间都有一个权值,现在从中选出一些区间使得所选区间的总权值最大,且所有区间上的数字被覆盖次数不能超过k次。

解题思路:

这是挑战书上的一道例题(p246),是一道费用流的题,不看题解我是想不到这道题如何构图的。

这道题的构图思想大致如下:

因为区间区间端点值很大,但是n很小,所以我们可以将区间离散化。离散化之后,端点有2*n个,大约最多400个。

我们将这些点排序,然后从前往后将第i个点和第i+1各点相连,设容量为无穷(这条边可以走多次,且可从这些边流向其他边),费用为0(对结果没影响)。然后按照给出的区间,将每个区间的端点进行连接,设容量为1(每个区间最多能取一次),费用设成-w(因为要求最大权值,我们将权值取反,求一次最小费用最大流,然后再将权值取反即是最大权值)。

最后,将1连向源点,容量为k(从源点开始流,因为其他边的流量为1,那么从源点最多可流k,即有k个增广路径,即使有的区间相交了,那么相交(覆盖)这部分最多被覆盖k次,所以这是可行的),费用为0,再将终点连向汇点,容量为k,费用为0。然后跑一边费用流即可。

如图所示,假设0是汇点在1之间有一条流量为k,费用为0的边,源点为5,在4之间有一条流量为k,费用为0的边。

假设k为1的时候,从原点到汇点只能走一条,按照费用流思想,会选择最大权值,既0-(-4-8)=12。

假设k为2的时候,先选2->3->4,再选1->3->4(3->4走的是无穷流边,因为流量为1的边已经走过了,没流了),答案为0-(-2-4-8)=14.

我这是简单说明一下,这样构图会保证每个子区间被覆盖的次数不超过k次且费用最大,但并没有体现费用流中加反向弧的精髓。

代码:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>
#include<iostream>
using namespace std;
#define maxn 500
#define inf 0x3f3f3f3f
struct Lu
{
    int to;
    int flow;
    int cost;
    Lu(int to=0,int flow=0,int cost=0):to(to),flow(flow),cost(cost) {}
};
vector<Lu>E;
vector<int>V[maxn];
int a[maxn];
int x[maxn];
int y[maxn];
int w[maxn];
int dis[maxn];
int vis[maxn];
int pre[maxn];
int spfa(int s,int t)
{
    for(int i=s; i<=t; i++)
    {
        pre[i]=-1;
        vis[i]=0;
        dis[i]=inf;
    }
    queue<int>Q;
    dis[s]=0;
    vis[s]=1;
    Q.push(s);
    int top,vlen;
    Lu L;
    while(!Q.empty())
    {
        top=Q.front();
        vis[top]=0;
        Q.pop();
        vlen=V[top].size();
        for(int i=0; i<vlen; i++)
        {
            L=E[V[top][i]];
            if(L.flow>0&&dis[L.to]>dis[top]+L.cost)
            {
                dis[L.to]=dis[top]+L.cost;
                pre[L.to]=V[top][i];
                if(!vis[L.to])
                {
                    vis[L.to]=1;
                    Q.push(L.to);
                }
            }
        }
    }
    if(dis[t]==inf)return 0;
    return 1;
}
int MinCostMaxFlow(int s,int t)
{

    int cost=0,minl=inf;
    while(spfa(s,t))
    {

        minl=inf;
        for(int i=pre[t]; i!=-1; i=pre[E[i^1].to])
        {
            //cout<<"+++"<<endl;
            minl=min(minl,E[i].flow);
        }
        for(int i=pre[t]; i!=-1; i=pre[E[i^1].to])
        {
            E[i].flow-=minl;
            E[i^1].flow+=minl;
            cost+=minl*E[i].cost;
        }

    }
    return 0-cost;
}
int main()
{
    int t,n,k,cnt;
    scanf("%d",&t);
    while(t--)
    {
        cnt=0;
        scanf("%d%d",&n,&k);
        for(int i=0; i<=2*n+2; i++)V[i].clear();
        E.clear();
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d",&x[i],&y[i],&w[i]);
            a[++cnt]=x[i];
            a[++cnt]=y[i];
        }
        sort(a+1,a+cnt+1);
        cnt=unique(a+1,a+cnt+1)-(a+1);
        //printf("%++d\n",cnt);
        for(int i=1; i<=n; i++)
        {
            x[i]=upper_bound(a+1,a+cnt+1,x[i])-(a+1);
            y[i]=upper_bound(a+1,a+cnt+1,y[i])-(a+1);
            //printf("%d %d\n",x[i],y[i]);
            E.push_back(Lu(y[i],1,0-w[i]));
            E.push_back(Lu(x[i],0,w[i]));
            V[y[i]].push_back(E.size()-1);
            V[x[i]].push_back(E.size()-2);
        }
        for(int i=1; i<cnt; i++)
        {
            E.push_back(Lu(i+1,inf,0));
            E.push_back(Lu(i,0,0));
            V[i+1].push_back(E.size()-1);
            V[i].push_back(E.size()-2);
        }
        E.push_back(Lu(1,k,0));
        E.push_back(Lu(0,0,0));
        V[1].push_back(E.size()-1);
        V[0].push_back(E.size()-2);
        E.push_back(Lu(cnt+1,k,0));
        E.push_back(Lu(cnt,0,0));
        V[cnt+1].push_back(E.size()-1);
        V[cnt].push_back(E.size()-2);
        int cost=MinCostMaxFlow(0,cnt+1);
        printf("%d\n",cost);
    }
}
/*
4
5 1
78 10000 1
78 100 1
79 10001 1
500 600 1
450 550 1
*/

猜你喜欢

转载自blog.csdn.net/zyy_1998/article/details/81449731