北京集训 区间覆盖 费用流

第三题区间覆盖(Interval)
(Interval.pas\c\cpp)
【问题描述】
有N 个开区间(ai,bi),每个区间有一个权值wi,现在请你选择其中的一些区
间,使得选出的区间权值总和最大,并满足数轴上的任意位置都被覆盖不超过K
次。

思路:最大费用最大流

先离散化

离散化后 第i个点和i+1个点连一条容量为K,费用为0的边

对于每个区间 ai到bi连一条容量为1 费用为wi的边

费用流求之

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<map>
  7 using namespace std;
  8 #define MAXN 500
  9 #define MAXM 2000
 10 int T,n,K,m,top;
 11 struct node
 12 {
 13     int u,remain,cost;
 14     node *next,*inv;
 15 };
 16 struct interval
 17 {
 18     int x,y,w;
 19 }a[MAXN];
 20 int b[MAXN],Q[9000000],d[MAXN],f[MAXN];
 21 node *graph[MAXN],*edge[MAXN],memo[MAXM];
 22 bool use[MAXN];
 23 map<int,int> home;
 24 void add(int x,int y,int r,int cost)
 25 {
 26     node *p=&memo[top++],*q=&memo[top++];
 27     p->u=y; p->remain=r; p->cost=cost; p->next=graph[x]; graph[x]=p;
 28     q->u=x; q->remain=0; q->cost=-cost; q->next=graph[y]; graph[y]=q;
 29     p->inv=q; q->inv=p;
 30 }
 31     
 32 void build_graph()
 33 {
 34     int i;
 35     for(i=1;i<=m;i++)
 36         add(i,i+1,K,0);
 37     for(i=1;i<=n;i++)
 38         add(a[i].x,a[i].y,1,a[i].w);
 39     m++;
 40 }
 41 
 42 bool SPFA()
 43 {
 44     int head,tail,u,v;
 45     memset(use,0,sizeof(use));
 46     memset(d,0xff,sizeof(d));
 47     d[1]=0; f[1]=-1;
 48     use[1]=1;
 49     Q[head=tail=1]=1;
 50     while(head<=tail)
 51     {
 52         u=Q[head++];
 53         for(node *p=graph[u];p;p=p->next)
 54         {
 55             v=p->u;
 56             if(p->remain>0&&d[u]+p->cost>d[v])
 57             {
 58                 d[v]=d[u]+p->cost;
 59                 f[v]=u;
 60                 edge[v]=p;
 61                 if(!use[v])
 62                     use[v]=1, Q[++tail]=v;
 63             }
 64         }
 65         use[u]=0;
 66     }
 67     //for(int i=1;i<=m;i++)
 68     //cout<<i<<" "<<d[i]<<endl;
 69     return d[m]>-1;
 70 }
 71 int extend()
 72 {
 73     int i,delta=123456789,res=0;
 74     for(i=m;f[i]!=-1;i=f[i])
 75         delta=min(delta,edge[i]->remain);
 76     for(i=m;f[i]!=-1;i=f[i])
 77     {
 78         edge[i]->remain-=delta;
 79         edge[i]->inv->remain+=delta;
 80         res+=edge[i]->cost*delta;
 81         ///cout<<i<<" "<<delta<<" "<<edge[i]->remain<<endl;
 82     }
 83     //cout<<res<<endl;
 84     return res;
 85 }
 86 int main()
 87 {
 88     freopen("interval.in","r",stdin);
 89     freopen("interval.out","w",stdout);
 90     int i,j;
 91     scanf("%d",&T);
 92     while(T--)
 93     {
 94         top=0;
 95         memset(graph,0,sizeof(graph));
 96         scanf("%d%d",&n,&K);
 97         for(i=1;i<=n;i++)
 98         {
 99             scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
100             b[i]=a[i].x; b[i+n]=a[i].y;
101         }
102         sort(b+1,b+2*n+1);
103         b[0]=-1;
104         j=0;
105         for(i=1;i<=2*n;i++)
106         {
107             if(b[i]!=b[i-1]) j++;
108             home[b[i]]=j;
109         }
110         m=j;
111         for(i=1;i<=n;i++)
112             a[i].x=home[a[i].x], a[i].y=home[a[i].y];
113         //for(i=1;i<=n;i++) cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].w<<endl;
114         //cout<<endl;
115         build_graph();
116         int sum=0;
117         while(SPFA()) 
118             sum+=extend();
119         printf("%d\n",sum);
120     }
121     return 0;
122 }
原文地址:https://www.cnblogs.com/myoi/p/2486477.html