Luogu P1361 small M's gift

Link:

P1361

Meaning:

There are \ (n \) points. They need to be divided into two point sets, and the contribution of each point in the two point sets is given. At the same time \ (m \) rules are given. Each rule gives some points. When these points are in the same point set, they will have additional contributions. The contributions of the points of each rule in the two point sets are given. Please maximize your contribution and.

analysis:

(pictures and ideas from Luogu)

The minimum cut can be used to divide some points into two point sets, so consider the minimum cut. Only minimize the "loss contribution".

If we divide a point into the point set on the left, the contribution on the right will be lost. Therefore, without considering additional rules, we can build such a model:

The middle is the point, and the flow of the left and right edges is the contribution to the left and right point set, so the minimum cut is the minimum "loss contribution".

Then consider additional rules.

The contribution of a rule to the point set can be divided into three cases: contribution to the point set \ (S \), contribution to the point set \ (T \), or no contribution, which means that we cannot deal with it through one state. We can consider it in two parts: contribution to \ (S \) and contribution to \ (T \).

Because this contribution cannot be connected to the existing edge, we first connect to an imaginary point and consider the contribution to \ (S \) separately. As long as a point is divided into the point set \ (T \), the contribution should be "lost", so each point should be connected to this imaginary point, so:

As long as a point is assigned to the point set \ (T \), the contribution should be "lost", so the "lost contribution" should be on the yellow side rather than the blue side. If a point \ (c \) is assigned to the point set \ (T \), any path from \ (S \) to \ (c \) should be disconnected. For \ (S\rightarrow X\rightarrow c \) , we want to cut off the yellow edge and keep the blue edge, so we set the flow of the yellow edge as the contribution. At the same time, in order to avoid cutting off the blue edge, we set its flow as inf.

The contribution to \ (T \) is the same, so the final model is:

To sum up:

The basic two take the problem model, that is, the minimum cut partition point set.

The application of virtual points is used to deal with some rules based on the basic model.

Algorithm:

Build a model and run the maximum flow.

The calculated minimum cut is the contribution of loss. The answer is obtained by subtracting the total contribution.

In addition, note that the number of points required by the topic is 3e3 and the number of sides is 2e6+4e3

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	int p=0,f=1;
	char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-'0';c=getchar();}
	return p*f;
}
const int N=3e3+5;
const int M=2e6+4e3+5;
const int inf=0x7fffffff;
int n,m,s,t,cnt,maxflow;
struct edge{
	int v,w,nxt;
}e[M<<1];
int head[N],en=1;
void insert(int u,int v,int w){
	e[++en].v=v;
	e[en].w=w;
	e[en].nxt=head[u];
	head[u]=en;
}
void add(int u,int v,int w){
	insert(u,v,w);
	insert(v,u,0);
}
int cur[N],dis[N];
queue<int> q;
bool bfs(){
	for(int i=1;i<=cnt;i++)
		dis[i]=0,cur[i]=head[i];
	while(!q.empty())q.pop();
	q.push(s);dis[s]=1;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u],v=e[i].v;i;i=e[i].nxt,v=e[i].v){
			if(!dis[v]&&e[i].w){
				dis[v]=dis[u]+1;
				if(v==t)return true;
				q.push(v);
			}
		}
	}
	return false;
}
int dfs(int u,int in){
	if(!in||u==t){return in;}
	int out=0;
	for(int i=cur[u],v=e[i].v;i;i=e[i].nxt,v=e[i].v){
		cur[u]=i;
		if(dis[v]!=dis[u]+1||!e[i].w)continue;
		int tmp=dfs(v,min(in-out,e[i].w));
		e[i].w-=tmp;
		e[i^1].w+=tmp;
		out+=tmp;
		if(in==out)break;
	}
	return out;
}
void dinic(){
	while(bfs()){maxflow+=dfs(s,inf);}
}
int ans;
signed main(){
	n=read();s=n+1,cnt=t=n+2;
	for(int i=1;i<=n;i++){int tmp=read();add(s,i,tmp);ans+=tmp;}
	for(int i=1;i<=n;i++){int tmp=read();add(i,t,tmp);ans+=tmp;}	
	m=read();
	for(int i=1,k,c;i<=m;i++){
		k=read();
		c=read();add(s,++cnt,c);ans+=c;
		c=read();add(++cnt,t,c);ans+=c;
		for(int j=1,x;j<=k;j++){
			x=read();
			add(cnt-1,x,inf);
			add(x,cnt,inf);
		}
	}
	dinic();
	cout<<ans-maxflow;
	return 0;
}
Digression:

Personally, I feel that modeling is more difficult than some template questions.

Posted on Tue, 02 Nov 2021 23:10:47 -0400 by Rushy