poj 3680 最小费用流

本文介绍了一种解决区间覆盖问题的最短路径算法实现方案,通过构建特殊图结构并运用SPFA算法来求解最小费用最大流问题,旨在使每个点被覆盖次数不超过预设值的同时,达到最小总成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:n个区间,每个区间都有权值,尽可能的去取区间,但要保证每个点不被取超过k次。

题解:

主要就是建图:我是不会建。。我太笨了。

首先,我们不可能每个点使其都存在。太多了。所以我们就取每个区间的端点。这样,每个端点之间的流量为k,费用为权值。但是,为了确保我们不想取这个区间时有别的选择,就把所有的点从小到大 连起来,流量为k,为用为0。这样当我们不想取某个区间时,就从费用为零的边上流过就行了。

另:要把端点离散化,排序,重编号。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#define MX 10000000
#define nMax 500
#define eMax 10000
using namespace std;
struct Egde{
	int u,v,c,w,next,pre; 
}eg[eMax];
int n, m, ans,vs,vt,cas,K;
int k, list[nMax];
int que[nMax], pre[nMax], dis[nMax];
struct interval{
	int x,y,w;
}inl[210];
int hash[100010];
bool vis[nMax];
void add(int u, int v, int c, int w){
	eg[k].u=u;eg[k].v=v;eg[k].pre=k+1;eg[k].next=list[u];eg[k].c=c;eg[k].w=w;list[u]=k++;
	eg[k].u=v;eg[k].v=u;eg[k].pre=k-1;eg[k].next=list[v];eg[k].c=0;eg[k].w=-w;list[v]=k++;
}
bool spfa(){                 
	int i, head = 0, tail = 1;
	for(i = vs; i <= vt; i ++){
		dis[i] = MX;
		vis[i] = false;
	}
	dis[vs] = 0;
	que[0] = vs;
	vis[vs] = true;
	while(tail != head){ 
		int u = que[head ++];
		for(i = list[u]; i != -1; i = eg[i].next){
			int v = eg[i].v;
			if(eg[i].c&& dis[v] > dis[u] + eg[i].w){
				dis[v] = dis[u] + eg[i].w;
				pre[v] = i;
				if(!vis[v]){
					vis[v] = true;
					que[tail ++] = v;
				}
			}
		}
		vis[u] = false;
	}
	if(dis[vt] == MX) return false;
	return true;
}
void end(){
	int u, p, sum = MX;
	for(u = vt; u != vs; u = eg[eg[p].pre].v){
		p = pre[u];
		eg[p].c -=1;
		eg[eg[p].pre].c += 1;
		ans +=-1*eg[p].w; 
	}
}
int main(){
	scanf("%d",&cas);
	while(cas--){
		k=0;
		ans = 0;
		memset(list,-1,sizeof(list));
		memset(hash,0,sizeof(hash));
		scanf("%d%d",&n,&K);
		int kk=1;
		for(int i=0;i<n;i++){
			scanf("%d%d%d",&inl[i].x,&inl[i].y,&inl[i].w);
			hash[inl[i].x]=hash[inl[i].y]=1;
		}
		for(int i=0;i<=100000;i++){
			if(hash[i]==1){
				hash[i]=kk++;
			}
		}
		for(int i=0;i<n;i++){
			inl[i].x=hash[inl[i].x];
			inl[i].y=hash[inl[i].y];
		}
		vs=0;vt=kk;
		for(int i=vs;i<vt;i++){
			add(i,i+1,K,0);
		}
		for(int i=0;i<n;i++){
			add(inl[i].x,inl[i].y,1,-inl[i].w);
		}
		while(spfa()) {
		end();
		}
		printf("%d\n",ans);
	}
return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值