zoukankan      html  css  js  c++  java
  • [CF802C]Heidi and Library (hard)

    题意

    你有一个容量为(k)的书架,每次给定一本书,如果集合中没有这个书就需要花费(c_i)的价格将这个书加入集合,可以随时丢掉集合内的书,求完成所有请求的最小花费

    题解

    为什么我一开始看到这题会想到最小割==
    但是每种物品是可以多次对答案造成贡献的,所以显然不能最小割,只能费用流了
    那么考虑怎么建图
    考虑买入有点困难
    可以考虑卖出,卖出的意义就是买入了一个原先有的东西
    那么我们把每个要求拆点
    拆成两个点(D_1,D_2)
    然后(S o D1)连流量为1,费用为这天物品的花费的边
    (D_1 o D_2)连流量为1,费用为0的边表示扔掉这本书
    (D2 o T)连流量为1,费用为0的边表示今天的物品是否扔掉
    (D_{i,1} o D_{i+1,1})连流量为(k-1),费用为0的边表示最多保留(k-1)本书,因为明天还要买入一本
    (D_{i-1,1} o D_{pre_i,2})表示已经有这本书了,可以把第(i)天出现的这本书卖掉了((pre_i)表示第(i)天出现的书上一个出现的时间)
    然后最小费用流即可

    代码

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 205 ;
    const int INF = 1e9 ;
    using namespace std ;
    
    inline int read() {
    	char c = getchar() ; int x = 0 , w = 1 ;
    	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    	return x*w ;
    }
    
    bool exist[M] ;
    int n , k , S , T , num = 1 , hea[M] ;
    int idx[M] , cst[M] , prep[M] , pos[M] ;
    int dis[M] , pre[M] , ans ;
    struct E {
    	int nxt , to , dis , cst ;
    } edge[M * 20] ;
    inline void Insert_edge(int from , int to , int dis , int cst) {
    	edge[++num].nxt = hea[from] ; edge[num].to = to ;
    	edge[num].dis = dis ; edge[num].cst = cst ; hea[from] = num ;
    }
    inline void add_edge(int u , int v , int w , int c) {
    	Insert_edge(u , v , w , c) ;
    	Insert_edge(v , u , 0 , -c) ;
    }
    inline bool Spfa() {
    	queue < int > q ; q.push(S) ; pre[T] = -1 ;
    	memset(dis , 63 , sizeof(dis)) ; dis[S] = 0 ;
    	while(!q.empty()) {
    		int u = q.front() ; q.pop() ; exist[u] = false ;
    		for(int i = hea[u] ; i ; i = edge[i].nxt) {
    			int v = edge[i].to ; 
    			if(dis[v] > dis[u] + edge[i].cst && edge[i].dis > 0) {
    				pre[v] = i ;
    				dis[v] = dis[u] + edge[i].cst ;
    				if(!exist[v]) {
    					exist[v] = true ;
    					q.push(v) ;
    				}
    			}
    		}
    	}
    	return (pre[T] > 0) ;
    }
    inline void Mcmf() {
    	while(Spfa()) {
    		int diss = INF ;
    		for(int i = T ; i != S ; i = edge[pre[i] ^ 1].to) 
    			diss = min(diss , edge[pre[i]].dis) ;
    		for(int i = T ; i != S ; i = edge[pre[i] ^ 1].to) 
    			edge[pre[i]].dis -= diss , edge[pre[i] ^ 1].dis += diss ;
    		ans += dis[T] * diss ;
    	}
    }
    int main() {
    	n = read() ; k = read() ; S = 0 ; T = n * 2 + 1 ;
    	for(int i = 1 ; i <= n ; i ++) {
    		idx[i] = read() ;
    		prep[i] = pos[idx[i]] ;
    		pos[idx[i]] = i ;
    	}
    	for(int i = 1 ; i <= n ; i ++) cst[i] = read() ;
    	for(int i = 1 ; i <= n ; i ++) {
    		add_edge(S , i * 2 - 1 , 1 , cst[idx[i]]) ;
    		add_edge(i * 2 - 1 , i * 2 , 1 , 0) ;
    		add_edge(i * 2 , T , 1 , 0) ;
    		if(i != n) add_edge(i * 2 - 1 , (i + 1) * 2 - 1 , k - 1 , 0) ;
    		if(prep[i]) add_edge((i - 1) * 2 - 1 , prep[i] * 2 , 1 , -cst[idx[i]]) ;
    	}
    	Mcmf() ;
    	printf("%d
    ",ans) ;
    	return 0 ;
    }
    
  • 相关阅读:
    nginx启动失败
    Windows下载安装docker详细步骤
    Consul
    Idea导入多个maven项目到同一目录下
    使用V-chart时踩过的一些坑
    java集合超详解
    HashMap
    curl和wget的区别和使用
    SourceTree3.2.6版本跳过注册办法
    单点登录
  • 原文地址:https://www.cnblogs.com/beretty/p/10726180.html
Copyright © 2011-2022 走看看