zoukankan      html  css  js  c++  java
  • AGC31E Snuke the Phantom Thief

    Snuke the Phantom Thief

    (N) 个珠宝,第 (i) 个位于 ((x_i, y_i)),价值为 (v_i)。你可以选择一些珠宝,有若干限制,每个限制形如如下四种之一:

    • (x ≤ a_i) 的珠宝只能选择不超过 (b_i) 个;

    • (x ≥ a_i) 的珠宝只能选择不超过 (b_i) 个;

    • (y ≤ a_i) 的珠宝只能选择不超过 (b_i) 个;

    • (y ≥ a_i) 的珠宝只能选择不超过 (b_i) 个;

    最大化选择的总价值。

    (1 ≤ N ≤ 80,1 ≤ x_i, y_i, a_i≤ 100)

    题解

    https://www.cnblogs.com/zhoushuyu/p/10548483.html

    首先这数据范围看着就很费用流

    先考虑一维怎么做。

    一个很妙的转化是:限制横坐标 (≤a_i) 的珠宝里至多选 (b_i) 个,等价于选择的横坐标第 (b_{i+1}) 小的珠宝,其横坐标必须 (>a_i)

    如果是限制横坐标 (≥a_i) 的珠宝至多选 (b_i) 个,则可以先枚举选 (s) 个珠宝,然后限制就等价于选择的第 (s-b_i) 个珠宝其横坐标必须 (<a_i)。(前述只考虑 (b_i < s) 的限制,(b_i ≥ s) 的限制显然无效)

    这样我们就可以得到 (s) 个二元组 ([l_j,r_j]),分别表示第 (j) 个珠宝的横坐标的范围限制。注意这 (s) 个二元组的 (l)(r) 应满足单调不降。

    这样我们就得到了一个匹配的模型:二分图一侧有 (s) 个点,另一侧有 (n) 个点,满足范围限制的点之间连边,然后求一组最大权匹配即可。

    至于二维的问题,可以直接把图拆成三份,即左侧 (s) 个点表示横坐标的限制,中间拆 (2n) 个点内部连权值的边表示珠宝,右侧另 (s) 个点表示纵坐标的限制。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define CO const
    #define IN inline
    typedef long long int64;
    
    template<class T> IN T read(){
    	T x=0,w=1;char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*w;
    }
    template<class T> IN T read(T&x){
    	return x=read<T>();
    }
    
    CO int N=400;
    CO int64 inf=1e18;
    namespace flow{
    	int n,S,T;
    	struct edge {int v,c;int64 w;int a;};
    	vector<edge> to[N];
    	int64 dis[N];int vis[N];
    
    	IN void init(int n){
    		flow::n=n,S=n-1,T=n;
    		for(int i=1;i<=n;++i) to[i].clear();
    	}
    	IN void link(int u,int v,int c,int64 w){
    		to[u].push_back({v,c,w}),to[v].push_back({u,0,-w});
    		to[u].back().a=to[v].size()-1,to[v].back().a=to[u].size()-1;
    	}
    	bool bfs(){
    		fill(dis+1,dis+n+1,-inf),dis[T]=0;
    		deque<int> Q={T};vis[T]=1;
    		while(Q.size()){
    			int u=Q.front();
    			Q.pop_front(),vis[u]=0;
    			for(CO edge&e:to[u])if(to[e.v][e.a].c){
    				if(dis[e.v]<dis[u]-e.w){ // edit 1: -w
    					dis[e.v]=dis[u]-e.w;
    					if(vis[e.v]) continue;
    					if(Q.size() and dis[e.v]>=dis[Q.front()])
    						Q.push_front(e.v);
    					else Q.push_back(e.v);
    					vis[e.v]=1;
    				}
    			}
    		}
    		return dis[S]>-inf;
    	}
    	int dfs(int u,int lim){
    		if(u==T) return lim;
    		vis[u]=1;
    		int rest=lim;
    		for(edge&e:to[u])if(!vis[e.v] and e.c and dis[e.v]==dis[u]-e.w){
    			int delta=dfs(e.v,min(e.c,rest));
    			if(!delta) {dis[e.v]=-inf;continue;}
    			rest-=delta,e.c-=delta,to[e.v][e.a].c+=delta;
    			if(!rest) break;
    		}
    		vis[u]=0;
    		return lim-rest;
    	}
    	int64 main(){
    		int64 ans=0;
    		while(bfs()) ans+=dfs(S,1e9)*dis[S];
    		return ans;
    	}
    }
    
    int n,X[N],Y[N];int64 V[N];
    int m,O[N],A[N],B[N];
    int L[N],R[N],D[N],U[N];
    
    int64 solve(int s){
    	fill(L+1,L+s+1,0),fill(D+1,D+s+1,0);
    	fill(R+1,R+s+1,233),fill(U+1,U+s+1,233); // edit 2: range of XY
    	for(int i=1;i<=m;++i)if(B[i]<s){
    		if(O[i]=='L') L[B[i]+1]=A[i]+1;
    		else if(O[i]=='R') R[s-B[i]]=A[i]-1;
    		else if(O[i]=='D') D[B[i]+1]=A[i]+1;
    		else U[s-B[i]]=A[i]-1;
    	}
    	for(int i=2;i<=s;++i){
    		L[i]=max(L[i],L[i-1]);
    		D[i]=max(D[i],D[i-1]);
    	}
    	for(int i=s-1;i>=1;--i){
    		R[i]=min(R[i],R[i+1]);
    		U[i]=min(U[i],U[i+1]);
    	}
    	flow::init(2*n+2*s+2);
    	for(int i=1;i<=n;++i) flow::link(i,i+n,1,V[i]);
    	for(int i=1;i<=s;++i){
    		flow::link(flow::S,i+2*n,1,0),flow::link(i+2*n+s,flow::T,1,0);
    		for(int j=1;j<=n;++j){
    			if(L[i]<=X[j] and X[j]<=R[i]) flow::link(i+2*n,j,1,0);
    			if(D[i]<=Y[j] and Y[j]<=U[i]) flow::link(j+n,i+2*n+s,1,0);
    		}
    	}
    	return flow::main();
    }
    int main(){
    	read(n);
    	for(int i=1;i<=n;++i) read(X[i]),read(Y[i]),read(V[i]);
    	read(m);
    	for(int i=1;i<=m;++i){
    		char opt[2];scanf("%s",opt);
    		O[i]=opt[0],read(A[i]),read(B[i]);
    	}
    	int64 ans=0;
    	for(int i=1;i<=n;++i) ans=max(ans,solve(i));
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    好久不写费用流都写不对了……

  • 相关阅读:
    hlgoj 1766 Cubing
    Reverse Linked List
    String to Integer
    Bitwise AND of Numbers Range
    Best Time to Buy and Sell Stock III
    First Missing Positive
    Permutation Sequence
    Next Permutation
    Gray Code
    Number of Islands
  • 原文地址:https://www.cnblogs.com/autoint/p/12204074.html
Copyright © 2011-2022 走看看