zoukankan      html  css  js  c++  java
  • CF103E Buying Sets

    https://www.luogu.com.cn/problem/CF103E

    有一个大小为 (n) 的全集,每个元素是一个数,有 (n) 个子集。题目保证任意 (k) 个子集的并的大小 (ge k)
    每个子集有一个可正可负的权值,你需要选出一些子集使得这些子集并的大小等于子集个数,且所选子集的权值和最小。可以为空集。

    考虑权值取负,然后变成最大化权值
    考虑建模使得 (S) 连到集合边权为权值,集合连到数边权无穷,数连到 (T) 边权 (0)
    这样割掉 (S) 的边即为不选某个集合,割掉 (T) 的边就是选某个数

    由于任意 (k) 个子集的并的大小 (ge k),可得割掉的边的数量一定不小于 (n)
    证明大概是,设左边割掉的集合为 (L),右边为 (R),则 (complement L) 所连向的右边的点的集合只能是 (R)
    则有 (|complement L|le |R|Rightarrow n-Lle RRightarrow nle L+R)

    但是要求 不选的集合和选的数 的个数相等,则可以让 (S) 连的边变成无穷加权值,(T) 连的边变成无穷,这样不会再割多余的边,就有了 (L+R=n)

    #define N 606
    #define M 360006
    struct Graph{
    	int fir[N],fir_[N],nex[M],to[M],tot;
    	long long w[M];
    	inline void add(int u,int v,long long W,int flag=1){
    		if(!tot) tot=1;
    		to[++tot]=v;w[tot]=W;
    		nex[tot]=fir[u];fir[u]=tot;
    		if(flag) add(v,u,0,0);
    	}
    }G;
    int S,T;
    int deep[N];
    int left,right,que[N];
    inline int bfs(){
    	std::memset(deep,0,sizeof deep);
    	left=right=0;
    	que[0]=S;deep[S]=1;
    	int u;
    	while(left<=right){
    		u=que[left++];
    		for(int v,i=G.fir[u];i;i=G.nex[i]){
    			v=G.to[i];
    			if(deep[v]||!G.w[i]) continue;
    			deep[v]=deep[u]+1;que[++right]=v;
    			if(v==T) return 1;
    		}
    	}
    	return 0;
    }
    long long dfs(int u,long long now=1e18){
    	if(u==T) return now;
    	long long res=now;
    	for(int v,&i=G.fir_[u];i;i=G.nex[i]){
    		v=G.to[i];
    		if(deep[v]!=deep[u]+1||!G.w[i]) continue;
    		long long k=dfs(v,std::min(res,G.w[i]));
    		if(!k) deep[v]=0;
    		else G.w[i]-=k,G.w[i^1]+=k,res-=k;
    		if(!res) break;
    	}
    	return now-res;
    }
    inline long long dinic(){
    	long long ans=0;
    	while(bfs()){
    		long long now;
    		std::memcpy(G.fir_,G.fir,sizeof G.fir);
    		while(now=dfs(S)) ans+=now;
    	}
    	return ans;
    }
    int main(){
    	int n=read();
    	S=n+n+1;T=S+1;
    	for(int k,i=1;i<=n;i++){
    		k=read();
    		while(k--) G.add(i,n+read(),LL_INF);
    		G.add(n+i,T,LL_INF);
    	}
    	long long sum=0;
    	for(int k,i=1;i<=n;i++){
    		k=-read();sum+=k;
    		G.add(S,i,LL_INF+k);
    	}
    	long long ans=dinic()-n*LL_INF;
    	printf("%d
    ",ans-sum);
    	return 0;
    }
    
  • 相关阅读:
    Echars折线配置详解
    Echarts中太阳图(Sunburst)的实例
    MongoDB shell 介绍
    js深度克隆对象
    js将有父子关系的数据转换成树形结构数据
    使用Mongoose类库实现简单的增删改查
    MongoDB可视化工具--Robo 3T 使用教程
    go语言之进阶篇并行和并发的区别与go语言并发优势
    go语言之进阶篇拷贝文件案例
    go语言之进阶篇借助bufio实现按行读取内容
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/15368489.html
Copyright © 2011-2022 走看看