題目:給定N個區間(ai,bi)權值wi,選一些區間,求最大權和且每個點最多覆蓋K次
做法是 先把所有的區間離散化 ,也就是隻留端點,然後排序,去重,標號。
增加超級源超級匯s,t.
假設剩下n個點, 加上超級源超級匯是n+2個。超級源爲0,匯爲n+1.
從0開始,順序建一條流量爲k,費用爲0的邊,將所有點串起來。然後再根據所輸入邊的信息,找到對應點的位置,連一條流量是1,費用是-w的邊,最後從s到t做最小費用。
比如說
3 1
1 3 2
2 3 4
3 4 8
將 1,3,2,3,3,4排序
變成 1 2 3 3 3 4
去重 1 2 3 4
然後 0->1 1->2 2->3 3->4 4->5 建邊
再 1->3 2->3 3->4 建邊 即可
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=1000 ;
const int M=5000 ;
const int inf=1<<30 ;
struct node
{
int u ,v,c,cost,next ;
}edge[M];
struct node1
{
int x,y,w;
}e[N] ;
int head[N],pp[N],pre[N],vist[N],dist[N] ,a[N];
int top ;
void add(int u ,int v,int c,int cost)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].cost=cost;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].cost=-cost;
edge[top].next=head[v];
head[v]=top++;
}
int SPFA(int s,int t)
{
int u , v ;
memset(vist,0,sizeof(vist));
memset(pre,-1,sizeof(pre));
for(int i = 0 ; i <= t ; i++) dist[i]=inf ;
vist[s]=1;dist[s]=0;pre[s]=s;
queue<int>q;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
vist[u]=0;
for(int i =head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c && dist[v] > dist[u]+edge[i].cost)
{
dist[v] = dist[u]+edge[i].cost ;
pre[v]=u;
pp[v]=i;
if(!vist[v]);
{
vist[v]=1;
q.push(v);
}
}
}
}
if(dist[t]==inf) return 0;
return 1 ;
}
int MFMC(int s,int t)
{
int mincost=0,flow=0,minflow ;
while(SPFA(s,t))
{
minflow=inf;
for(int i=t;i!=s;i=pre[i])
minflow=min(minflow,edge[pp[i]].c);
for(int i=t;i!=s;i=pre[i])
{
edge[pp[i]].c -= minflow;
edge[pp[i]^1].c += minflow;
}
flow += minflow;
mincost += dist[t]*minflow ;
// printf("****");
}
return -mincost ;
}
int main()
{
int T,n,k,cnt ;
scanf("%d",&T);
while(T--)
{
top = 0; cnt=0;
memset(head,-1,sizeof(head)) ;
memset(a,0,sizeof(a)) ;
scanf("%d%d",&n,&k);
for(int i = 0 ; i < n ; i++)
{
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w) ;
a[cnt++]=e[i].x ; a[cnt++]=e[i].y ;
}
sort(a,a+cnt) ;
int tmp = 1 ;
for(int i = 1 ; i < cnt ; i++)
{
if(a[i]!=a[i-1])
a[tmp++]=a[i];
}
for(int i = 1 ; i < tmp ; i++)
{
add(i,i+1,k,0) ;
}
for(int i = 0 ; i < n ;i++)
{ //返回大於或等於e[i].x的第一個元素下標位置
int u = lower_bound(a,a+tmp,e[i].x)-a;
int v = lower_bound(a,a+tmp,e[i].y)-a;
add(u+1,v+1,1,-e[i].w) ; //數組a從0開始 ,所以要加1,0號留給 S ;
}
int s = 0 ,t = tmp+1 ;
add(s,1,k,0);
add(tmp,t,k,0) ;
int ans = MFMC(s,t) ;
printf("%d\n",ans);
}
return 0;
}