POJ3680最小费用最大流

题目:给定N个区间(ai,bi)权值wi,求最大权和且每个点最多覆盖K次。

构图:将区间端点离散化为(1,2,3.....G)

         源点0 汇点G+1

         addedge(i,i+1,k,0)  容量k , 费用0  ,用以限制最多覆盖K次

   再处理N个区间离散化后的(ai,bi),addedge(ai,bi,1,-wi);


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main {
	public static void main(String[] args) {
		new POJ3680().solve();
	}
}

class POJ3680{

	InputReader in = new InputReader(System.in);
	PrintWriter out = new PrintWriter(System.out); 
	final int N = 208 ;
	int[] a = new int[N] ;
	int[] b = new int[N] ;
	int[] w = new int[N] ;
	Hash hash = new Hash() ;
	MinCostMaxFlow mcmf = new MinCostMaxFlow() ;

	void solve() {
		int t = in.nextInt() ;
		while(t-- > 0){
			hash.clear() ; 
			int n = in.nextInt() ;
			int k = in.nextInt() ;
			for(int i = 1 ; i <= n ; i++){
				a[i] = in.nextInt() ;
				b[i] = in.nextInt() ;
				w[i] = in.nextInt() ;
				hash.add(a[i]) ;
				hash.add(b[i]) ;
			}
			hash.toArray() ;
			int src = 0 ;
			int meet = hash.size() + 1 ;
			mcmf.clear(meet) ;
			for(int i = 0 ; i < meet ; i++)
				mcmf.addedge(i , i+1 , k , 0) ;
			for(int i = 1 ; i <= n ; i++)
				mcmf.addedge(hash.getId(a[i]) , hash.getId(b[i]) , 1 , -w[i]) ;
			
			mcmf.doMCMF(src , meet) ;
			out.println(-mcmf.minCost) ;	
		}
		out.flush() ;	
	}

}

class Hash{
	
	TreeSet<Integer> tree = new TreeSet<Integer>() ;
	int[] array ;
	void clear(){
		tree.clear() ;
	}
	
	void add(int x){
		tree.add(x) ;
	}
	
	int size(){
		return tree.size() ;
	}
	
	void toArray(){
		array = new int[tree.size()] ;
		int idx = 0 ;
		for(int i : tree) array[idx++] = i ;
	}
	
	int getId(int key){
		return Arrays.binarySearch(array , key) + 1  ;
	}
}



class MinCostMaxFlow{
	final int MAXN = 1010;
	final int MAXM = 10010;
	final int INF = 0x3f3f3f3f ;
	class Edge{
		int to,next,cap,flow,cost ;
		public Edge(int to , int cap , int cost , int flow , int next) {
			this.to = to ;
			this.cap = cap ;
			this.cost = cost ;
			this.flow = flow ;
			this.next = next ;
		}
	}
	Edge[] edge = new Edge[MAXM] ;
	int[] head = new int [MAXN] ;
	int tol ;
	int[] pre = new int[MAXN] ;
	int[] dis = new int[MAXN] ;
	boolean[] vis = new boolean[MAXN] ;
	int N;
	
	void clear(int n){ 
		N = n + 2 ;
		tol = 0;
		Arrays.fill(head , -1) ;
	}
	
	void addedge(int u,int v,int cap,int cost){
		edge[tol] = new Edge(v, cap, cost, 0, head[u]) ;
		head[u] = tol++;
		edge[tol] = new Edge(u, 0, -cost, 0, head[v]) ;
		head[v] = tol++;
	}

	boolean spfa(int s,int t)
	{
		Queue<Integer> q = new LinkedList<Integer>() ;
		for(int i = 0 ; i < N ; i++){
			dis[i] = INF ;
			vis[i] = false ;
			pre[i] = -1 ;
		}
		dis[s] = 0 ;
		vis[s] = true ;
		q.add(s) ;
		while(! q.isEmpty()){
			int u = q.poll() ;
			vis[u] = false ;
			for(int i = head[u] ; i != -1 ; i = edge[i].next){
				int v = edge[i].to ;
				if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost){
					dis[v] = dis[u] + edge[i].cost ;
					pre[v] = i ;
					if(! vis[v]){
						vis[v] = true;
						q.add(v);
					}
				}
			}
		}
		if(pre[t] == -1)return false; //找不到一条增广路径
		else return true;
	}

	int maxFlow ;
	int minCost ;
	void doMCMF(int s,int t){
		maxFlow = 0 ;
		minCost = 0 ;
		while(spfa(s , t)){
			int Min = INF ;
			for(int i = pre[t] ; i != -1 ; i = pre[edge[i^1].to])
				Min = Math.min(Min ,  edge[i].cap - edge[i].flow) ;

			for(int i = pre[t] ; i != -1 ; i = pre[edge[i^1].to]){
				edge[i].flow += Min;
				edge[i^1].flow -= Min;
				minCost += edge[i].cost * Min ;
			}
			maxFlow += Min ;
		}
	}
}


class InputReader {
	public BufferedReader reader;
	public StringTokenizer tokenizer;

	public InputReader(InputStream stream) {
		reader = new BufferedReader(new InputStreamReader(stream), 32768);
		tokenizer = null;
	}

	public String next() {
		while (tokenizer == null || !tokenizer.hasMoreTokens()) {
			try {
				tokenizer = new StringTokenizer(reader.readLine());
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		return tokenizer.nextToken();
	}

	public int nextInt() {
		return Integer.parseInt(next());
	}

	public long nextLong() {
		return Long.parseLong(next());
	}

	public double nextDouble() {
		return Double.parseDouble(next());
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值