洛谷P3358:最长k可重区间集问题(最大费用最大流)
2018-03-04 10:08
375 查看
题目
对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度。
题解
我先给大家解释一下开区间,意思就是有区间集合(a,b),这个集合除去点a,b所构成的集合称为开区间(a,b)。
这道题看上去很复杂,其实就是可以转化为找k个集合,每个集合内的区间互不相交。
我这么一说,悟性高的同志都跑去打mcmf板子了。
先按照左端点为第一关键字,右端点为第二关键字,排一次序,每个区间拆成两个点,用来控制流量和制造费用。a区间拆成a点和a'点。
1.对于每个区间,i到i'连一条流量为1费用为长度的边,表示选择这条边会获得长度的价值。
2.对于每两个区间i,j(1<=i<j<=n),i'到j连一条流量为1费用为0的边,表示选择i区间时可以选择j区间。
3.xbegin到i连一条流量为1费用为0的边,i'到end连一条流量为1费用为0的边。
4.最后别忘了”只能选择k个集合“这个条件,超超超级源begin到xbegin连一条流量为k费用为0的边。
贴代码#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define INF 1e9
using namespace std;
int n,k;
int begin,end;
struct node{int x,y;};
node p[1010];
int first[1010];
struct edge{int x,y,c,cos,next;};
edge s[100010];
int len=1;
queue<int> f;
int h[1010];
bool tf[1010];
int mmin[1010];
int ip[1010];
void ins(int x,int y,int c,int cos)
{
len++;
s[len].x=x;s[len].y=y;s[len].c=c;s[len].cos=cos;s[len].next=first[x];first[x]=len;
len++;
s[len].x=y;s[len].y=x;s[len].c=0;s[len].cos=-cos;s[len].next=first[y];first[y]=len;
}
bool check(int x,int y)
{
if(p[x].y<=p[y].x) return true;
return false;
}
bool SPFA(int&cost,int&flow)
{
f.push(begin);
memset(h,63,sizeof(h));
h[begin]=0;
mmin[begin]=INF;
tf[begin]=true;
while(!f.empty())
{
int x=f.front();
f.pop();
tf[x]=false;
for(int i=first[x];i!=0;i=s[i].next)
{
int y=s[i].y;
if(h[y]>h[x]+s[i].cos && s[i].c>0)
{
h[y]=h[x]+s[i].cos;
ip[y]=i;
mmin[y]=min(mmin[x],s[i].c);
if(tf[y]==false)
{
tf[y]=true;
f.push(y);
}
}
}
}
if(h[end]==1061109567) return false;
flow+=mmin[end];
cost+=mmin[end]*h[end];
int now=end;
while(now!=begin)
{
int i=ip[now];
s[i].c-=mmin[end];
s[i^1].c+=mmin[end];
now=s[i].x;
}
return true;
}
int cost_flow()
{
int cost=0,flow=0;
while(SPFA(cost,flow));
return -cost;
}
void qsort(int x,int y)
{
int i=x,j=y;
node m,t;
m=p[(x+y)/2];
while(i<=j)
{
while(p[i].x<m.x) i++;
while(p[j].x>m.x) j--;
if(i<=j)
{
t=p[i];p[i]=p[j];p[j]=t;
i++;j--;
}
}
if(x<j) qsort(x,j);
if(i<y) qsort(i,y);
}
int main()
{
scanf("%d %d",&n,&k);
begin=n*2+1,end=n*2+2;
ins(begin,0,k,0);
for(int i=1;i<=n;i++)
scanf("%d %d",&p[i].x,&p[i].y);
qsort(1,n);
for(int i=1;i<=n;i++)
{
int x=p[i].x,y=p[i].y;
ins(0,i,INF,0);
ins(n+i,end,INF,0);
ins(i,n+i,1,-(y-x));
for(int j=i+1;j<=n;j++)
if(check(i,j))
ins(n+i,j,1,0);
}
printf("%d",cost_flow());
}
对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度。
题解
我先给大家解释一下开区间,意思就是有区间集合(a,b),这个集合除去点a,b所构成的集合称为开区间(a,b)。
这道题看上去很复杂,其实就是可以转化为找k个集合,每个集合内的区间互不相交。
我这么一说,悟性高的同志都跑去打mcmf板子了。
先按照左端点为第一关键字,右端点为第二关键字,排一次序,每个区间拆成两个点,用来控制流量和制造费用。a区间拆成a点和a'点。
1.对于每个区间,i到i'连一条流量为1费用为长度的边,表示选择这条边会获得长度的价值。
2.对于每两个区间i,j(1<=i<j<=n),i'到j连一条流量为1费用为0的边,表示选择i区间时可以选择j区间。
3.xbegin到i连一条流量为1费用为0的边,i'到end连一条流量为1费用为0的边。
4.最后别忘了”只能选择k个集合“这个条件,超超超级源begin到xbegin连一条流量为k费用为0的边。
贴代码#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define INF 1e9
using namespace std;
int n,k;
int begin,end;
struct node{int x,y;};
node p[1010];
int first[1010];
struct edge{int x,y,c,cos,next;};
edge s[100010];
int len=1;
queue<int> f;
int h[1010];
bool tf[1010];
int mmin[1010];
int ip[1010];
void ins(int x,int y,int c,int cos)
{
len++;
s[len].x=x;s[len].y=y;s[len].c=c;s[len].cos=cos;s[len].next=first[x];first[x]=len;
len++;
s[len].x=y;s[len].y=x;s[len].c=0;s[len].cos=-cos;s[len].next=first[y];first[y]=len;
}
bool check(int x,int y)
{
if(p[x].y<=p[y].x) return true;
return false;
}
bool SPFA(int&cost,int&flow)
{
f.push(begin);
memset(h,63,sizeof(h));
h[begin]=0;
mmin[begin]=INF;
tf[begin]=true;
while(!f.empty())
{
int x=f.front();
f.pop();
tf[x]=false;
for(int i=first[x];i!=0;i=s[i].next)
{
int y=s[i].y;
if(h[y]>h[x]+s[i].cos && s[i].c>0)
{
h[y]=h[x]+s[i].cos;
ip[y]=i;
mmin[y]=min(mmin[x],s[i].c);
if(tf[y]==false)
{
tf[y]=true;
f.push(y);
}
}
}
}
if(h[end]==1061109567) return false;
flow+=mmin[end];
cost+=mmin[end]*h[end];
int now=end;
while(now!=begin)
{
int i=ip[now];
s[i].c-=mmin[end];
s[i^1].c+=mmin[end];
now=s[i].x;
}
return true;
}
int cost_flow()
{
int cost=0,flow=0;
while(SPFA(cost,flow));
return -cost;
}
void qsort(int x,int y)
{
int i=x,j=y;
node m,t;
m=p[(x+y)/2];
while(i<=j)
{
while(p[i].x<m.x) i++;
while(p[j].x>m.x) j--;
if(i<=j)
{
t=p[i];p[i]=p[j];p[j]=t;
i++;j--;
}
}
if(x<j) qsort(x,j);
if(i<y) qsort(i,y);
}
int main()
{
scanf("%d %d",&n,&k);
begin=n*2+1,end=n*2+2;
ins(begin,0,k,0);
for(int i=1;i<=n;i++)
scanf("%d %d",&p[i].x,&p[i].y);
qsort(1,n);
for(int i=1;i<=n;i++)
{
int x=p[i].x,y=p[i].y;
ins(0,i,INF,0);
ins(n+i,end,INF,0);
ins(i,n+i,1,-(y-x));
for(int j=i+1;j<=n;j++)
if(check(i,j))
ins(n+i,j,1,0);
}
printf("%d",cost_flow());
}
相关文章推荐
- 【网络流24题】No.21 (最长 k 可重区间集问题 最长不相交路径 最大费用流)
- 洛谷P3358 最长k可重区间集问题(费用流)
- 线性规划与网络流24题之最长k可重区间集问题 最大权不相交路径(最大费用最大流)
- 洛谷 P3358 最长k可重区间集问题 【最大费用最大流】
- 【POJ3680】【离散化+费用流 思维】 Intervals 区间图的最大权问题
- 洛谷P3357:最长k可重线段集问题(最大费用最大流)
- nefu495最长k可重区间集问题【最大权不相交路径】网络流24题
- 【网络流24题】No.11(航空路线问题 最长不相交路径 最大费用流)
- 【COGS743】最长k可重区间集问题 最大权不相交路径
- loj6227「网络流 24 题」最长k可重线段集问题(类似loj6014 费用流)
- 【网络流24题】最长k可重区间集问题
- 【codevs1906】最长递增子序列问题 最大流
- 北京网赛I题 hiho1391 (树状数组、区间覆盖最大值问题)
- 网络流24题之最长k可重区间集问题
- 连续最大和,数字类区间问题
- ★ 最长递增子序列问题 (最多不相交路径)(分层思想) 网络流最大流
- 洛谷 P3356 火星探险问题 【最大费用最大流】
- 线性规划与网络流24题の18 分配问题(最小费用最大流、最大费用最大流)
- POJ 3264 ST表(RMQ问题:查询区间最大最小值)
- 2014湘潭全国邀请赛I题 Intervals /POJ 3680 / 在限制次数下取有权区间使权最大/小问题(费用流)