您的位置:首页 > 其它

POJ 3680 Intervals

2010-12-04 09:30 218 查看
如果不是看到分类用最小费用流来做,我自己肯定想不到。。。

一开始想的构图是每个区间作为一个顶点,源点向每个区间连一条容量为1的边,然后找一些集合,每个集合代表一段区间,对于所有在这个区间内相交错的区间,向该集合代表的顶点连一条容量为1的边,然后每个集合顶点向汇点连一条容量为k的边

但问题是那些区间集合没有什么好的方法可以确定,看了网上别人的思路,很巧妙

先将区间离散化,将左右端点号从小到大排序,去掉重复的,然后每个端点对应一个点,第i个端点向第i+1个端点连一条容量为k的边

源点向第一个顶点连容量为k的边,最后一个端点向汇点连一条容量为k的边,费用都为0,然后对于每个区间,找到他们左右端点在图中的顶点好,从小的向大的连一条容量为1,费用为该区间权值的边

实际上当流到达一个顶点的时候,可以选择分配是否分配流,由于顶点已排序,大区间正好覆盖小区间,边上的容量限制也符合了题目中每个点覆盖的次数(转化为所在区间)

然后跑一次最大费用最大流即可

代码:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAX 405
const int inf=1<<29;
struct edge
{
int u,v,c,f,b,next;
}g[200000];
struct node
{
int l,r,cost;
}interval[MAX];
int adj[MAX],dis[MAX],pre[MAX],r[MAX];
bool vis[MAX];
int s,t,n,k,vn,ans,e,cnt;
void add(int u,int v,int c,int b)
{
g[e].u=u; g[e].v=v; g[e].c=c; g[e].f=0; g[e].b=b; g[e].next=adj[u]; adj[u]=e++;
g[e].u=v; g[e].v=u; g[e].c=0; g[e].f=0; g[e].b=-b; g[e].next=adj[v]; adj[v]=e++;
}
int find(int x)
{
int low=1,high=cnt,mid;
while(low<high)
{
mid=(low+high)/2;
if(r[mid]<x)
low=mid+1;
else
high=mid;
}
return low;
}
void build()
{
int i,j,a,b;
memset(adj,-1,sizeof(adj));
e=0;
s=0;
t=cnt+1;
for(i=1;i<=cnt;i++)
{
add(i,i+1,k,0);
}
add(s,1,k,0);
add(cnt,t,k,0);
for(i=1;i<=n;i++)
{
a=find(interval[i].l);
b=find(interval[i].r);
add(a,b,1,interval[i].cost);
}
}
void spfa()
{
int i,j,cur;
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(s);
vis[s]=true;
while(!q.empty())
{
i=q.front();
q.pop();
vis[i]=false;
for(cur=adj[i];cur!=-1;cur=g[cur].next)
{
j=g[cur].v;
if(g[cur].c>g[cur].f&&dis[j]<dis[i]+g[cur].b)
{
dis[j]=dis[i]+g[cur].b;
pre[j]=cur;
if(!vis[j])
{
vis[j]=true;
q.push(j);
}
}
}
}
}
void solve()
{
int i,j,minf;
ans=0;
while(true)
{
memset(dis,-1,sizeof(dis));
memset(pre,-1,sizeof(pre));
dis[s]=0;
spfa();
if(dis[t]==-1)
break;
minf=inf;
for(i=pre[t];i!=-1;i=pre[g[i].u])
{
minf=min(minf,g[i].c-g[i].f);
}
for(i=pre[t];i!=-1;i=pre[g[i].u])
{
g[i].f+=minf;
g[i^1].f-=minf;
}
ans+=minf*dis[t];
}
printf("%d/n",ans);
}
int main()
{
int i,j,test;
scanf("%d",&test);
while(test--)
{
j=0;
scanf("%d %d",&n,&k);
for(i=1;i<=n;i++)
{
scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].cost);
r[++j]=interval[i].l;
r[++j]=interval[i].r;
}
sort(r+1,r+j+1);
cnt=0;
for(i=1;i<=j;i++)
{
if(cnt==0||r[cnt]!=r[i])
r[++cnt]=r[i];
}
build();
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: