题目链接:http://poj.org/problem?id=3680
题意描述:给你n(n<=200)个区间,每个区间有一个权值,且每个区间的实数点最多只能访问k次,现在让你选择区间使得所选权值和最大
分析:该题是最大费用最大流,k可以看成是容量限制,刚开始这样想,将给出的每个区间看成一个点,然后将区间(i,i+1)i从0一直取到最大看成一些点,那么源点连接每个给出区间点,自己创造的区间点连接汇点,每个区间点都对应一些自己创造的区间点,但是这样做,不能正确的确定边的容量和费用,所以这样是解不出来的,无赖只好百度了一下,网上的建图方法经典至极啊,是将区间看成一条边而我只停留在将区间看成点的程度上,将区间看成边,那么对于这样的区间(i,i+1)那么他们最多允许流过k次,费用设为0,那么对给出区间的区间,这样的边就可以流过的流量设为1,表示只能选择一次,费用自然是区间的权值,现在这里给出建图的方法:建图之前可以将区间点离散化一下,这样可以减少些点,使得点最多不超过402个,那么我们建立源点和汇点,源点连接第一个点容量为k,费用为0,最后一个点连接汇点费用为0,容量为k,之间相邻的点相连,费用为0,容量为k,此处建图就体现了区间中所有的点最多只能流过k次,即最多只能被覆盖k次,之后对于给出的区间,我们连接区间的两个端点,容量为1,如果求最小费用则费用这里取反,否则为正!假设我们求最大费用最大流,我们每次都找源点到汇点的费用最长路,且每次找出一条路径都会将其经过的区间覆盖一次,如果不存在增广路则意味着不能在继续选区间啦!
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=410;
const int E=20000;
const int inf=0x3fffffff;
struct node
{
int x, y,nxt,c,w;
}edge[E];
int head[N],e;
int src,sin;
struct node1
{
int x, y,c;
}a[N/2];
int b[N];
void addedge(int x,int y, int w, int c)
{
edge[e].x=x;
edge[e].y=y;
edge[e].w=w;
edge[e].c=c;
edge[e].nxt=head[x];
head[x]=e++;
edge[e].x=y;
edge[e].y=x;
edge[e].w=0;
edge[e].c=-c;
edge[e].nxt=head[y];
head[y]=e++;
}
int find(int x,int high)
{
int low=1;
while(low<=high)
{
int mid=(low+high)>>1;
if(b[mid]==x)
return mid;
if(b[mid]<x)
low=mid+1;
else high=mid-1;
}
}
int dis[N],que[N],pre[N];
int Cost,Flow;
bool isque[N];
void mincmaxf()
{
Cost=0;Flow=0;int u,v,i;
while(1)
{
int f=0,r=1;
for(i=src;i<=sin;i++)
{
dis[i]=inf;
isque[i]=false;
}
dis[src]=0;
que[0]=src;
isque[src]=true;
while(f!=r)
{
u=que[f];
f=(f+1)%N;
for(i=head[u];i!=-1;i=edge[i].nxt)
{
v=edge[i].y;
if(dis[v]>dis[u]+edge[i].c&&edge[i].w)
{
dis[v]=dis[u]+edge[i].c;
pre[v]=i;
if(!isque[v])
{
que[r]=v;
r=(r+1)%N;
isque[v]=true;
}
}
}
isque[u]=false;
}
if(dis[sin]==inf)break;
int p,min=inf;
for(u=sin;u!=src;u=edge[pre[u]].x)
{
p=pre[u];
if(min>edge[p].w)
min=edge[p].w;
}
Flow+=min;
Cost+=min*dis[sin];
for(u=sin;u!=src;u=edge[pre[u]].x)
{
p=pre[u];
edge[p].w-=min;
edge[p^1].w+=min;
}
}
}
int main ()
{
int t,n,k,i,j,x,y,c;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
memset(head,-1,sizeof(head));
e=0;
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
b[i*2-1]=a[i].x;
b[i*2]=a[i].y;
}
sort(b+1,b+2*n+1);
for(i=2,j=2;i<=2*n;i++)
if(b[i]!=b[i-1])
b[j++]=b[i];
sin=j;src=0;
for(i=0;i<j;i++)
addedge(i,i+1,k,0);
for(i=1;i<=n;i++)
{
x=find(a[i].x,j-1);
y=find(a[i].y,j-1);
if(x>y)swap(x,y);
addedge(x,y,1,-a[i].c);
}
mincmaxf();
printf("%d\n",-Cost);
}
return 0;
}