NOI 2006 最大获利


\(Link\)

题意略。

对于每个用户群 \(i\),考虑选不选它。

如果选,则中转站 \(A_i,B_i\) 必选。

然后就有最大权闭合子图的影子了。

接下来建一个二分图,左边点为用户群 \(X\),右边为中转站 \(Y\)

对于每个 \(X_i\),其点权为 \(C_i\)

对于每个 \(Y_i\),其点权为 \(-P_i\)

然后对于每个用户群 \(X_i\),让它对 \(Y_{A_i},Y_{B_i}\) 连一条边。

求这张图的最大权闭合子图就行了。

\(Code:\)

// Problem: P4174 [NOI2006] 最大获利
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4174
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 

#include
using namespace std;
#define ll long long
#define f(i,a,b) for(ll i=a;i<=b;i++)
#define wt int tt=d;while(tt--)
#define py puts("Yes")
#define pn puts("No")
#define fe(i,e) for(int i=0;i
inline ll rd() {
	ll x=0,f=1;
	char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c))x=x*10+c-'0',c=getchar();
	return x*f;
}
#define d rd()
#define pb push_back
struct edge{ll v,w,nx;}e[1000010];
ll hd[200010],cnt=1;
void add(ll u,ll v,ll w){e[++cnt]=(edge){v,w,hd[u]};hd[u]=cnt;}
ll qp(ll a,ll b,ll p){
	ll ans=1;while(b){
		if(b&1)ans=ans*a%p;
		a=a*a%p;b>>=1;
	}return ans;
}ll s,t,n,m;
bool vis[200010];
ll de[200010],ans;
bool to;
ll cur[200010];
bool Dinic_bfs(){
	queueq;
	f(i,1,t)cur[i]=hd[i],de[i]=0x3f3f3f3f,vis[i]=0;de[s]=0;
	ll ppp=de[t];
	q.push(s);vis[s]=1;while(!q.empty()){
		ll u=q.front();q.pop();vis[u]=0;
		for(int i=hd[u];i;i=e[i].nx){
			ll v=e[i].v;
			if(de[v]>de[u]+1&&e[i].w){
				de[v]=de[u]+1;if(!vis[v])q.push(v),vis[v]=1;
			}
		}
	}if(de[t]==ppp)return 0;
	return 1;
}ll Dinic_dfs(ll u,ll flo){
	if(u==t){
		to=1;ans+=flo;
		return flo;
	}ll used=0;
	ll now=0;
	for(int i=cur[u];i;i=e[i].nx){
		ll v=e[i].v;cur[u]=i; 
		if(e[i].w&&de[v]==de[u]+1){
			if(now=Dinic_dfs(v,min(flo-used,e[i].w))){
				used+=now;e[i].w-=now;e[i^1].w+=now;
				if(used==flo)break;
			}
		}
	}return used;
}void Dinic(){while(Dinic_bfs())Dinic_dfs(s,1000000000000);}
ll Ans;
int main(){
	n=d,m=d;s=n+m+1,t=n+m+2;
	f(i,1,n){ll x=d;add(m+i,t,x),add(t,m+i,0);}
	f(i,1,m){
		ll u=d,v=d,w=d;
		add(i,u+m,1000000000000),add(u+m,i,0);
		add(i,v+m,1000000000000),add(v+m,i,0);
		add(s,i,w),add(i,s,0);Ans+=w;
	}Dinic();printf("%lld\n",Ans-ans);
	return 0;
}

ps:CF1082G是双倍经验。