zoukankan      html  css  js  c++  java
  • CF103E

    有一点tricky的东西,不是很难。
    做法1:用jzoj一道题的做法。
    考虑最大权闭合子图对每个集合拆点(i),每个元素拆点(i+n)
    则集合(i)选择,(S_i)的每个元素都要选择。
    (i)的代价为(m_i)(i+n)的代价为(0)
    这是经典的最大权闭合子图,但是要求任意(i)个集合的并的元素个数必定是(i),不太能做。
    由于规定了任意(i)个集合的并的元素个数必定大于等于(i),任意(i)个集合的并的元素个数-(igeq 0)
    也就是说对于每个子集,任意(i)个集合的并的元素个数(-i)的最小值等于(0)(这很难想到)
    于是可以修改上面的网络流模型,用(inf)限制任意(i)个集合的并的元素个数(-i)的最小值等于(0)
    设一个选择方案的代价为价值减去(inf*)限制任意(i)个集合的并的元素个数(-i)的最小值,则(inf*)限制任意(i)个集合的并的元素个数(-i)的最小值必须为(0)才最优。
    于是修改成(i)的代价为(m_i+inf)(i+n)的代价为(-inf)即可。
    最小权只需要费用取反即可。
    做法2:我在思考那道题时的一个想法。
    这个做法本质和做法1相同。
    可以用一个二元组表示选择方案的代价:((a,b))表示价值为(b),集合的并的元素个数-(i)(a)
    比较时先比较(a)再比较(b)
    两个二元组((a,b)+(c,d))的加法定义为((a+c,b+d))
    两个二元组的最小值定义为((a-c,b-d))(不能定义为((a-min(a,c),b-min(b,d)))
    (i)的代价为((1,m_i))(i+n)的代价为((-1,0)),把每条边的代价也设为二元组,最大流即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 400010
    #define M 400010
    #define int long long
    int h[M],nxt[M],v[M],w[M],s,t,dep[M],ec,n,p[N],T,a[N],ans;
    char st[N];
    void add(int a,int b,int c){v[++ec]=b;w[ec]=c;nxt[ec]=h[a];h[a]=ec;}
    void adj(int a,int b,int c){
    	add(a,b,c);
    	add(b,a,0);
    }
    int id(int x,int y){
    	return (x-1)*n+y;
    }
    bool bfs(){
        queue<int>q;
    	q.push(s);
        for(int i=1;i<=t;i++)
        	dep[i]=0;
    	dep[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=h[x];i;i=nxt[i])
                if(w[i]&&!dep[v[i]]){
                	dep[v[i]]=dep[x]+1;
    				q.push(v[i]);
                	if(v[i]==t)
    					return 1;
    			}
        }
    	return 0;
    }
    int dfs(int x,int dis){
        if(x==t)
    		return dis;
    	int tp=dis;
        for(int i=h[x];i;i=nxt[i])
            if(dep[v[i]]==dep[x]+1&&w[i]){
                int f=dfs(v[i],min(tp,w[i]));
                if(!f)
    				dep[v[i]]=0;
                tp-=f;
                w[i]-=f;
    			w[i^1]+=f;
                if(!tp)
    				break;
            }
        return dis-tp;
    }
    int din(){
        int aans=0;
        while(bfs()){
        	int v;
        	while(v=dfs(s,1e9))
    			aans+=v;
    	}
        return aans;
    }
    signed main(){
    	ec=1;
    	scanf("%lld",&n);
    	int ans=0;
    	t=n+n+1;
    	for(int i=1;i<=n;i++){
    		int c,x;
    		scanf("%lld",&c);
    		for(int j=1;j<=c;j++){
    			scanf("%lld",&x);
    			adj(x+n,i,1e13);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&a[i]);
    		adj(i,t,1e9-a[i]);
    		ans+=1e9-a[i];
    		adj(s,i+n,1e9);
    	}
    	printf("%lld
    ",din()-ans);
    }
    
    
  • 相关阅读:
    armlinuxgnueabihf、aarch64linuxgnu等ARM交叉编译GCC的区别
    《JAVA与模式》之简单工厂模式
    wget常用命令
    sublime text添加Jquery插件
    e = e || window.event用法细节讨论
    配置运行 Compilify.net
    [翻译].NET中的Command(命令)模式
    EF Code First 中使用Jarek Kowalski's Provider的方法1
    WF实例学习笔记:(1)准备工作
    Entity Framework Code First Caching
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14880310.html
Copyright © 2011-2022 走看看