码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3680 Intervals

时间:2020-01-15 21:33:25      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:while   代码   流量   n+2   for   mem   mes   main   als   

题意

有n个线段\((a_i,b_i)\),每个线段有一个权值\(w_i\)。要求选若干个线段,使得数轴上每个点至多被k个线段包含。

建图

可以把权值取负值作为费用求费用流,这题有两种建图方式

  1. 离散化数据,对每个点i连一条i到i+1的边,流量为k,费用为0。对于所有线段连一条\(a_i\)\(b_i\)的边,流量为1,费用为-\(w_i\)。那么,对每个点可以选择以这个点为起点的线段或者不选,如果选了就需要花费1个流量,且直到线段终点都只剩下了k-1个流量,所以可以确保每一个点最多被k条线段覆盖。

  2. 考虑把线段覆盖改为找k个不相交的线段集合。把每个点拆成两个,这样就可以对所有不相交的线段进行连边。并且对每个线段的起点终点连边(费用为-w),源点对线段起点连边,线段终点对汇点连边。这样线段集合就表示为了一条增广路。最后在源点或汇点加一个限制(流量为k的边)就可以了。

代码

  1. #include<vector>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=200+5;
    int a[maxn],b[maxn],ww[maxn];
    vector<int>vec;
    
    struct Edge{
        int v,w,c,next;
    }edge[maxn*6];
    int head[maxn*2],ecnt;
    void add(int u,int v,int w,int c)
    {
        edge[ecnt]=(Edge){v,w,c,head[u]};
        head[u]=ecnt++;
    }
    
    const int inf=0x3f3f3f3f;
    int S,T;
    int fa[maxn*2],fai[maxn*2];
    int dis[maxn*2], vis[maxn*2];
    bool spfa()
    {
        memset(dis,0x3f,sizeof(dis));
        queue<int>q;
        dis[S]=0;
        for(q.push(S);!q.empty();q.pop())
        {
            int u=q.front();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].v;
                if(!edge[i].w)continue;
                if(dis[v]>dis[u]+edge[i].c)
                {
                    dis[v]=dis[u]+edge[i].c;
                    fa[v]=u;
                    fai[v]=i;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return dis[T]!=inf;
    }
    
    int cost()
    {
        int ans=0,flow=inf;
        for(int u=T;u!=S;u=fa[u])
            flow=min(flow,edge[fai[u]].w);
        for(int u=T;u!=S;u=fa[u])
        {
            edge[fai[u]].w-=flow;
            edge[fai[u]^1].w+=flow;
            ans+=flow*edge[fai[u]].c;
        }
        return ans;
    }
    
    int main()
    {
        int ca;
        scanf("%d",&ca);
        while(ca--)
        {
            int N,K;
            vec.clear();
            memset(head,-1,sizeof(head));
            ecnt=0;
            scanf("%d%d",&N,&K);
            for(int i=1;i<=N;i++)
            {
                scanf("%d%d%d",&a[i],&b[i],&ww[i]);
                vec.push_back(a[i]);
                vec.push_back(b[i]);
            }
            sort(vec.begin(),vec.end());
            int n=unique(vec.begin(),vec.end())-vec.begin();
            vec.resize(n);
            for(int i=1;i<=N;i++)
            {
                a[i]=lower_bound(vec.begin(),vec.end(),a[i])-vec.begin()+1;
                b[i]=lower_bound(vec.begin(),vec.end(),b[i])-vec.begin()+1;
    
                add(a[i],b[i],1,-ww[i]);
                add(b[i],a[i],0,ww[i]);
            }
            for(int i=0;i<=n;i++)
            {
                add(i,i+1,K,0);
                add(i+1,i,0,0);
            }
            S=0;T=n+1;
            int ans=0;
            while(spfa())
                ans+=cost();
            printf("%d\n",-ans);
        }
        return 0;
    }
  2. #include<vector>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=200+5;
    int a[maxn],b[maxn],ww[maxn];
    
    struct Edge{
        int v,w,c,next;
    }edge[maxn*maxn*2];
    int head[maxn*2],ecnt;
    void add(int u,int v,int w,int c)
    {
        edge[ecnt]=(Edge){v,w,c,head[u]};
        head[u]=ecnt++;
        edge[ecnt]=(Edge){u,0,-c,head[v]};
        head[v]=ecnt++;
    }
    
    const int inf=0x3f3f3f3f;
    int S,T;
    int fa[maxn*2],fai[maxn*2];
    int dis[maxn*2], vis[maxn*2];
    bool spfa()
    {
        memset(dis,0x3f,sizeof(dis));
        queue<int>q;
        dis[S]=0;
        for(q.push(S);!q.empty();q.pop())
        {
            int u=q.front();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].v;
                if(!edge[i].w)continue;
                if(dis[v]>dis[u]+edge[i].c)
                {
                    dis[v]=dis[u]+edge[i].c;
                    fa[v]=u;
                    fai[v]=i;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return dis[T]!=inf;
    }
    
    int cost()
    {
        int ans=0,flow=inf;
        for(int u=T;u!=S;u=fa[u])
            flow=min(flow,edge[fai[u]].w);
        for(int u=T;u!=S;u=fa[u])
        {
            edge[fai[u]].w-=flow;
            edge[fai[u]^1].w+=flow;
            ans+=flow*edge[fai[u]].c;
        }
        return ans;
    }
    
    int main()
    {
        int ca;
        scanf("%d",&ca);
        while(ca--)
        {
            int N,K;
            memset(head,-1,sizeof(head));
            ecnt=0;
            scanf("%d%d",&N,&K);
            S=0,T=2*N+2;
            for(int i=1;i<=N;i++)
            {
                scanf("%d%d%d",&a[i],&b[i],&ww[i]);
                add(i*2,i*2+1,1,-ww[i]);
                add(i*2,i*2+1,inf,0);//
                add(S+1,i*2,1,0);
                add(i*2+1,T,1,0);
            }
            add(S,S+1,K,0);
            for(int i=1;i<=N;i++)
                for(int j=1;j<=N;j++)
                    if(b[i]<=a[j])
                        add(2*i+1,2*j,inf,0);
            int ans=0;
            while(spfa())
                ans+=cost();
            printf("%d\n",-ans);
        }
        return 0;
    }

POJ 3680 Intervals

标签:while   代码   流量   n+2   for   mem   mes   main   als   

原文地址:https://www.cnblogs.com/intmian/p/12198798.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!