Network flow problem selection

Posted by kycan on Fri, 29 Oct 2021 08:46:35 +0200

There are boards here

Maximum flow

view code
namespace Flow
{
	int tot=1,fi[N],ne[M],to[M],w[M],S,T,d[N],nn;
	inline void add(int x,int y,int c)
	{
		ne[++tot]=fi[x],fi[x]=tot,to[tot]=y,w[tot]=c;
		ne[++tot]=fi[y],fi[y]=tot,to[tot]=x,w[tot]=0;
	}
	inline bool bfs()
	{
		fill(d+1,d+nn+1,-1);d[S]=0;
		queue<int>q;q.push(S);
		while(!q.empty())
		{
			int u=q.front();q.pop();
			for(int i=fi[u];i;i=ne[i])
			{
				int v=to[i];
				if(d[v]<0&&w[i])
					d[v]=d[u]+1,q.push(v);
			}
		}
		return d[T]!=-1;
	}
	int dfs(int u,int flow)
	{
		if(!flow||u==T)return flow;
		int used=0;
		for(int i=fi[u];i;i=ne[i])
		{
			int v=to[i];
			if(d[v]!=d[u]+1)continue;
			int t=dfs(v,min(w[i],flow-used));
			w[i]-=t,w[i^1]+=t;
			used+=t;
			if(used==flow)break;
		}
		if(used<flow)d[u]=-1;
		return used;
	}
	inline int dinic()
	{
		int e=0;
		while(bfs())e+=dfs(S,inf);
		return e;
	}
}
using namespace Flow;

Cost flow

view code
namespace Flow
{
	int tot=1,S,T,nn,fi[N],ne[M],to[M],c[M],pot[N],pre[N],f[N],w[M],dis[N];bool inq[N];
	inline void add(int x,int y,int s,int wt)
	{
		ne[++tot]=fi[x],fi[x]=tot,to[tot]=y,c[tot]=s,w[tot]=wt;
		ne[++tot]=fi[y],fi[y]=tot,to[tot]=x,c[tot]=0,w[tot]=-wt;
	}
	inline bool spfa()
	{
		fill(dis+1,dis+nn+1,-inf);dis[S]=0;
		queue<int>q;q.push(S);inq[S]=1;f[S]=inf;
		while(!q.empty())
		{
			int u=q.front();q.pop();inq[u]=0;
			for(int i=fi[u];i;i=ne[i])
			{
				int v=to[i];
				if(c[i]&&dis[v]<dis[u]+w[i])
				{
					dis[v]=dis[u]+w[i];
					pre[v]=u,pot[v]=i^1;
					f[v]=min(c[i],f[u]);
					if(!inq[v])q.push(v),inq[v]=1;
				}
			}
		}
		return dis[T]!=-inf;
	}
	inline pair<int,int> dinic()
	{
		int cost=0;int F=0;
		while(spfa())
		{
			int now=T,flow=f[T];F+=flow;
			while(now!=S)
			{
				cost+=w[pot[now]^1]*flow;
				c[pot[now]]+=flow;
				c[pot[now]^1]-=flow;
				now=pre[now];
			}
		}
		return make_pair(F,cost);
	}
}
using namespace Flow;

Part 1

A class of network flow problems satisfy the following properties:

  • There are several elements, and each element has two states (black or white, select or deselect ···). It is required to select one of them, and selecting one has corresponding benefits
  • There are several restrictions or additional benefits. For example, if the \ (X \) state of \ (A \) is selected, the \ (Y \) state of \ (B \) cannot be selected or the \ (X \) state of \ (A \) and the \ (Y \) state of \ (B \) can bring additional benefits of \ (w \).
  • Finally, the maximum income is required.

The routine of this problem is to select all benefits first, and then subtract the minimum cut of the constructed graph (meaning the minimum cost that has to be given up) (in this minimum cut, select one state in the source point set and another state in the sink point set), which is the final answer.

This may be a bit abstract. The following topics are of this type for easy understanding.

[national training team]

description

A \ (n\times m \) seat table with one classmate in each seat. For each student, choosing liberal arts or science has a certain joy value. At the same time, for two students adjacent to each other, if they choose liberal arts or science at the same time, they will bring additional joy. Find the maximum joy value.

solution

Consider how to use the minimum cut to represent the minimum cost that has to be given up.

Establish super source and super sink to represent liberal arts and science respectively. For each student to build points separately, if it belongs to the source point set in the minimum cut, it means that he chooses liberal arts, otherwise he chooses science.

The connection capacity from the source point to each student is the edge of selecting the joy value of liberal arts, and the connection capacity from each student to the sink point is the edge of selecting the joy value of science. In this way, cutting the edge of the source point represents giving up the weight brought by liberal arts and finally choosing science; Cut off the edge of the meeting point.

Then consider the additional weight. It is still a routine. For each additional weight, a new point is established. If this weight is related to the selected liberal arts, the edge with the weight capacity is connected from the source point to it, and the edge with the capacity \ (\ infty \) is connected to the corresponding students. In this way, if one of the students finally belongs to the meeting point set (equivalent to choosing Science), the edge connected by the meeting point will be broken, which means giving up this additional weight.

The final answer is the initial weight and minus the minimum cut.

code

view code
int n,m,ans,o;
inline int id(int x,int y){return (x-1)*n+y+2;}
int main()
{
	scanf("%d%d",&n,&m);S=1,T=2;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			scanf("%d",&o),ans+=o,add(S,id(i,j),o);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			scanf("%d",&o),ans+=o,add(id(i,j),T,o);
	nn=n*m+2;
	for(int i=1;i<n;++i)
		for(int j=1;j<=m;++j)
		{
			int p=++nn;
			scanf("%d",&o);ans+=o;
			add(S,p,o),add(p,id(i,j),inf),add(p,id(i+1,j),inf);
		}
	for(int i=1;i<n;++i)
		for(int j=1;j<=m;++j)
		{
			int p=++nn;
			scanf("%d",&o);ans+=o;
			add(p,T,o),add(id(i,j),p,inf),add(id(i+1,j),p,inf);
		}
	for(int i=1;i<=n;++i)
		for(int j=1;j<m;++j)
		{
			int p=++nn;
			scanf("%d",&o);ans+=o;
			add(S,p,o),add(p,id(i,j),inf),add(p,id(i,j+1),inf);
		}
	for(int i=1;i<=n;++i)
		for(int j=1;j<m;++j)
		{
			int p=++nn;
			scanf("%d",&o);ans+=o;
			add(p,T,o),add(id(i,j),p,inf),add(id(i,j+1),p,inf);
		}
	printf("%d\n",ans-dinic());
	return 0;
}

Grid access problem

solution

This is a limited situation.

According to the routine, first select all the weights, and then delete some points at the least cost to make the rest feasible.

If we connect a lattice with its adjacent lattice, then the problem is transformed into the weighted maximum independent set of the graph.

According to the black-and-white coloring, it can be found that this graph must be a bipartite graph. In that case, it can be done.

The edge is connected from the source point to the black point, and the capacity is its weight; The white point is connected to the sink point, and the capacity is its weight. Black dots are connected to adjacent white dots with a capacity of \ (\ infty \). Any path from the source point to the sink point is illegal. We only need to cut the edge with the minimum cost to make it disconnected, which conforms to the definition of the minimum cut. So it was done.

code

view code
int n,m,ans;
const int fx[]={0,0,1,-1},fy[]={1,-1,0,0};
inline bool ok(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
inline int id(int x,int y){return (x-1)*m+y;}
int main()
{
	scanf("%d%d",&n,&m);nn=n*m;
	S=++nn,T=++nn;int d;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
		{
			scanf("%d",&d);ans+=d;
			int now=id(i,j);
			if((i+j)&1)add(S,now,d);
			else{add(now,T,d);continue;}
			for(int k=0;k<4;++k)
			{
				int x=i+fx[k],y=j+fy[k];
				if(ok(x,y))add(now,id(x,y),inf);
			}
		}
	printf("%d\n",ans-dinic());
	return 0;
}

[BJOI2016] crystal

solution

The original coordinates are annoying because the coordinates and positions do not correspond one by one. So you can convert \ ((x,y,z)\rightarrow(x-z,y-z) \) (reason: vector addition follows the parallelogram rule). Plane obtuse coordinate system???

Note that there are still \ (x+y+z\equiv x-z+y-z\pmod 3 \) after such conversion.

It is not difficult to find that the \ (a \) resonance and \ (b \) resonance together are equivalent to that there cannot be three adjacent positions \ ((x_1,y_1),(x_2,y_2),(x_3,y_3) \) satisfied

\[x_1+y_1\equiv 1\pmod 3\\ x_2+y_2\equiv 0\pmod 3\\ x_3+y_3\equiv 2\pmod 3\\ \]

Therefore, for each crystal, first remove the point, which is divided into input point and output point, and connect the edge with the weight of capacity from input point to output point.

The crystals are then classified according to the remainder of the sum of the abscissa and ordinate values divided by \ (3 \). The module \ (3 \) is adjacent to the module \ (1 \), the module \ (3 \) is adjacent to the module \ (0 \), and the module \ (3 \) is adjacent to the module \ (0 \), and the module \ (3 \) is adjacent to the module \ (2 \), with a capacity of \ (\ infty \).

Then, the source point is connected to the point where the module \ (3 \) is \ (1 \), and the module \ (3 \) is connected to the sink point where the module \ (2 \), with a capacity of \ (\ infty \).

With the analysis method similar to the previous question, the final answer is the total weight minus the minimum cut.

Note: 1. The definitions in this question are slightly different from those in other topics. 2. If there are multiple crystals in the same point, special treatment is required.

code

view code
const int fx[]={0,0,1,-1,1,-1},fy[]={1,-1,0,0,1,-1};
map<pair<int,int>,int>mp,buc;
int x[P],y[P],tp[P],n,ans;
int main()
{
	scanf("%d",&n);
	for(int i=1,z,v;i<=n;++i)
	{
		scanf("%d%d%d%d",&x[i],&y[i],&z,&v);
		x[i]-=z,y[i]-=z;
		tp[i]=(x[i]+y[i])%3;tp[i]=(tp[i]+3)%3;
		v*=10;if(!tp[i])v=v/10*11;ans+=v;
		buc[make_pair(x[i],y[i])]+=v;
	}
	n=buc.size();int now=0;
	for(auto it=buc.begin();it!=buc.end();it++)
	{
		++now,add(now,now+n,it->second);
		x[now]=(it->first).first,y[now]=(it->first).second;
		tp[now]=(x[now]+y[now])%3;tp[now]=(tp[now]+3)%3;
		mp[it->first]=now;
	}
	nn=2*n;S=++nn;T=++nn;
	for(int i=1;i<=n;++i)
	{
		if(tp[i]==2)add(i+n,T,inf);
		else if(tp[i]==1)
		{
			add(S,i,inf);
			for(int k=0;k<6;++k)
			{
				int nx=x[i]+fx[k],ny=y[i]+fy[k];
				if(!mp.count(make_pair(nx,ny)))continue;
				int id=mp[make_pair(nx,ny)];
				if(tp[id])continue;
				add(i+n,id,inf);
			}
		}
		else
		{
			for(int k=0;k<6;++k)
			{
				int nx=x[i]+fx[k],ny=y[i]+fy[k];
				if(!mp.count(make_pair(nx,ny)))continue;
				int id=mp[make_pair(nx,ny)];
				if(tp[id]!=2)continue;
				add(i+n,id,inf);
			}
		}
	}
	printf("%.1lf",(ans-dinic())/10.0);
	return 0;
}

Part 2

The maximum weight closed subgraph problem is described as follows:

For a point weighted \ (DAG \) graph, its closed subgraph is defined as a point set \ (S \). If \ (u\in S \), all the points that can be reached by \ (u \) belong to \ (S \). The maximum weight closed subgraph is the point weight and maximum closed subgraph.

How to solve?? Or follow the previous routine, first select the weights of all positive weight points, and then establish the minimum cut model. From the source point to the positive weight point, connect the edges with the capacity of their weights, and from the negative weight point to the sink point, connect the edges with the capacity of the opposite number of their weights, and then keep the edges of the original graph with the capacity of \ (\ infty \).

The final answer is the weight of all positive weight points minus the minimum cut. In the minimum cut, the edge connected to the positive weight point without being cut indicates that this point is selected, and the edge connected by the negative weight point indicates that this point is selected. It is not difficult to find that this must meet the conditions.

[NOI2009] plants vs Zombies

solution

Each plant is regarded as a point, and the point weight is its income. If the plant \ (a \) protects the plant \ (b \), the edge \ (b\rightarrow a \) means eating \ (a \) and then eating \ (b \).

Note that the model built in this way has rings, but the model just introduced does not allow rings. Therefore, the topological sorting can remove the rings, and then apply the above model.

Note that the graph created by topological sorting happens to be the inverse of the graph we need to create. Pay a little attention.

code

view code
int n,m,val[P*P],deg[P*P];bool flag[P*P],G[P*P][P*P];
inline int id(int x,int y){return (x-1)*m+y;}
vector<int>e[P*P];
inline void adde(int x,int y){e[x].push_back(y);}
inline void topo()
{
	nn=n*m;
	for(int i=1;i<=nn;++i)
		for(int v:e[i])++deg[v];
	queue<int>q;
	for(int i=1;i<=nn;++i)
		if(!deg[i])q.push(i),flag[i]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int v:e[u])
			if(!(--deg[v]))
				flag[v]=1,q.push(v);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		for(int j=1,w,x,y;j<=m;++j)
		{
			int now=id(i,j);
			scanf("%d%d",&val[now],&w);
			while(w--)
				scanf("%d%d",&x,&y),
				adde(now,id(x+1,y+1));
		}
	for(int i=1;i<=n;++i)
		for(int j=2;j<=m;++j)
			adde(id(i,j),id(i,j-1));
	topo();
	for(int u=1;u<=nn;++u)
	{
		if(!flag[u])continue;
		for(int v:e[u])
			if(flag[v]&&!G[v][u])add(v,u,inf),G[v][u]=1;
	}
	S=++nn,T=++nn;int ans=0;
	for(int u=1;u<=n*m;++u)
	{
		if(!flag[u])continue;
		if(val[u]>0)add(S,u,val[u]),ans+=val[u];
		else add(u,T,-val[u]);
	}
	printf("%d\n",ans-dinic());
	return 0;
}

Part 3

Look directly at the example.

The longest k-repeatable interval set problem

solution

The model is more classic, so a close-up question solution is written to deepen the impression.

It is easy to think of cost flow, but how to model is the key. We can transform the whole process as follows: initially, there are \ (k \) individuals and \ (n \) pieces of work. The duration of each work is \ ((l_i,r_i) \), only one person is required to do it, and this person can't do other work when doing this work, but completing this work completely can obtain \ (w_i \). Now you need to arrange reasonably to maximize the sum of benefits. This problem is only another form of the original problem, which is essentially the same, but the modeling is more convenient: that is, establish the position edge of the super source point to 0 on the number axis, the flow is \ (k \) and the cost is 0. Then, for each point on the number axis \ (I \) to \ (i+1 \), the flow is \ (k \) and the cost is 0. Then connect the edge from the largest point on the number axis to the super sink. Finally, for each interval, connect from \ (l_i \) to \ (r_i \), the flow is 1, and the cost is \ (w_i \). The answer is to run out of the maximum cost feasible flow. When the value range is relatively large, it can be discretized first.

The problem of the longest k-repeatable segment set

solution

This question is essentially the same as the previous one, except that the section perpendicular to the \ (x \) axis is not the same. For this problem, you can directly disassemble points, but a simpler way is to expand the domain. It means that we now have not only whole points, but also points such as \ (\ dfrac d2 \) (\ (d \) is an odd number). In order to maintain the original intersection / disjoint relationship, just change \ ((l,r) \) of \ (l=r \) to \ ((l,r+0.5) \), \ (l\not=r \) to \ ((l,r) \). Then align the coordinates with the unified \ (\ times 2 \) and it will be exactly the same as the previous question.

Part 4

Some miscellaneous questions??

[RC-02] open the door

description

There are \ (n \) individuals and \ (m \) sets of questions. If the \ (I \) individual does the \ (j \) set of questions, the weight of \ (g_{i,j} \) will be generated. Now there are several requirements. Each requirement is in the form of \ (i\ j\ k \), which means that the number of the question done by the \ (I \) is at least \ (k \) greater than that done by the \ (j \). Now everyone should be assigned a set of questions to make the total weight as small as possible.

solution

The minimum total weight is associated with the minimum cut model.

Remove the points. Divide each person \ (I \) into \ (m+1 \) points, and the flow of the edge connected \ ((i,j)\rightarrow(i,j+1) \) is \ (g_{i,j} \). Cutting off this edge represents the cost incurred by the \ (I \) individual doing the \ (J \) set of questions.

In addition, because a person can only do one set of questions, in order to ensure that only one edge is cut for a person, we also need to connect the edge \ ((i,j)\leftarrow (i,j+1) \) with the edge weight of \ (\ infty \). In this way, if the minimum cut is cut twice, it will lead to contradiction:

Because it is the minimum cut, the two edges of the cut must be useful, that is, they are connected with the source point in front and the sink point in the back. However, because there is a reverse edge, the latter one is connected to the source point, and then you can go over to the sink point. It is a cut contradiction with.

Then, connect the source point to all \ ((i,1) \) and the flow is \ (\ infty \)\ ((i,m+1) \) connects to the confluence, and the flow is \ (\ infty \).

The key now is how to meet the requirements.

For the requirement \ ((i,j,k) \), we need to connect the sides \ ((j,x)\rightarrow(i,x+k)(1\le x,x+k\le m+1) \) with a flow of \ (\ infty \). In this case, if you choose to cut it off at \ ((j,x)\rightarrow (j,x+1) \), it must be cut off at \ (\ ge x+k \) due to the existence of the path \ (S\rightarrow(j,1)\rightarrow(j,x)\rightarrow(i,x+k)\rightarrow(i,m+1)\rightarrow T \).

code

view code
int n,m,p,y,c[P];
db a[P][P];
inline int id(int x,int y){return (x-1)*(m+1)+y;}
int main()
{
	int t;scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d%d",&n,&m,&p,&y);
		for(int i=1;i<=p;++i)scanf("%d",c+i),c[i]+=c[i-1];
		for(int j=1;j<=m;++j)
			for(int i=1;i<=n;++i)
			{
				a[i][j]=0;db now=1.0,x;
				for(int k=1;k<=p;++k)
				{
					scanf("%lf",&x);
					a[i][j]+=c[k-1]*now*(1-x);
					now*=x;
				}
				a[i][j]+=c[p]*now;
			}
		pre(n*(m+1)+2);
		for(int i=1;i<=n;++i)
		{
			add(S,id(i,1),inf),add(id(i,m+1),T,inf);
			for(int j=1;j<=m;++j)
				add(id(i,j),id(i,j+1),a[i][j]),
				add(id(i,j+1),id(i,j),inf);
		}
		while(y--)
		{
			int x,y,k;scanf("%d%d%d",&x,&y,&k);
			for(int i=1;i<=m;++i)
				if(i+k>=1&&i+k<=m+1)
					add(id(y,i),id(x,i+k),inf);
		}
		db ans=dinic();
		if(sig(inf-ans)<=0)puts("-1");
		else printf("%.4lf\n",ans);
	}
	return 0;
}

CF277E Binary Tree on Plane

solution

Remove the points. A point is divided into an in point and an out point.

The source node connects to all incoming nodes. The edge with a capacity of \ (2 \) and a cost of \ (0 \) represents at most two sons of the node.

All outgoing points are connected to sink points. The capacity is \ (1 \) and the cost is \ (0 \), which means that the node has at most one parent.

Then, for a point \ (i \), its incoming point connects to all outgoing points that can be its son \ (j \), with a capacity of \ (1 \) and a cost of its distance, which means that at most one edge can be selected at the cost of its distance.

Finally, run the minimum cost maximum flow. Note that only the root has no father, so there is a solution if and only if the maximum flow is \ (n-1 \).

code

view code
int n,x[P],y[P];
inline int sq(int a){return a*a;}
inline db d(int a,int b){return sqrt(sq(x[a]-x[b])+sq(y[a]-y[b]));}
int main()
{
	scanf("%d",&n);init(2*n+2);
	for(int i=1;i<=n;++i)
		scanf("%d%d",x+i,y+i);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			if(y[j]<y[i])
				add(i,j+n,1,d(i,j));
	for(int i=1;i<=n;++i)
		add(S,i,2,0),add(i+n,T,1,0);
	auto ans=dinic();
	if(ans.first<n-1)puts("-1");
	else printf("%.15lf\n",ans.second);
	return 0;
}

[NOI2012] Food Festival

solution

First, the total waiting time needs to be converted. Assuming that there is only one master and the time spent on cooking is \ (t_1,t_2,\cdots t_k \), the total waiting time is

\[\sum_{i=1}^kt_i+\sum_{i=2}^kt_i+\cdots \sum_{i=k}^kt_i=\sum_{j=1}^k\sum_{i=j}^kt_i=\sum_{i=1}^kt_i(k-i+1) \]

In human terms, if the current dish is made in the last \ (p \), its contribution to the total waiting time is \ (pt \)

So we can build the map happily. Remember \ (sum = \ sum {I = 1} ^ np_i \), then divide each chef \ (I \) into \ (sum \) points to represent the chef \ (I \) to cook the last \ (J \) dish. From the source point to each dish, the capacity is \ (p_i \) and the cost is \ (0 \); Each dish is connected to the order just removed (cook \ (J \) makes the last (k \) dish), with a capacity of \ (1 \) and a cost of \ (t_{j, k} \ times, k \); These points are connected to the sink point with a capacity of \ (1 \) and a cost of \ (0 \). Finally, running a minimum cost maximum flow is the answer.

This model may solve many similar problems.

But for this problem, building a map directly like this will \ (T \). Consider optimization. In fact, we don'T have to dismantle so many points at all, because it's impossible for every cook to have \ (sum \) dishes. Notice the nature that for the same chef, he must cook the last (k) dish first, and then the last (k+1) dish may be cooked. So at the beginning, we only use the side of the penultimate dish, and then expand it once. We check each chef to see if he has finished the penultimate dish. If so, add the side of the penultimate dish, and so on. It is similar to the dynamic open point of data structure.

code

view code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,M=1e7+5,inf=0x3f3f3f3f,P=105;
int m,n,t[P][P],p[P],sum,now[P],id[P];
namespace Flow
{
	int tot=1,S,T,nn,fi[N],ne[M],to[M],c[M],pot[N],pre[N],f[N],w[M],dis[N];bool inq[N];
	inline void add(int x,int y,int s,int wt)
	{
		ne[++tot]=fi[x],fi[x]=tot,to[tot]=y,c[tot]=s,w[tot]=wt;
		ne[++tot]=fi[y],fi[y]=tot,to[tot]=x,c[tot]=0,w[tot]=-wt;
	}
	inline void adde(int i,int pos)
	{
		int cur=++nn;
		for(int k=1;k<=n;++k)
			add(k+2,cur,inf,t[i][k]*pos);
		add(cur,T,1,0);now[i]=pos;id[i]=cur;
	}
	inline bool spfa()
	{
		fill(dis+1,dis+nn+1,inf);dis[S]=0;
		queue<int>q;q.push(S);inq[S]=1;f[S]=inf;
		while(!q.empty())
		{
			int u=q.front();q.pop();inq[u]=0;
			for(int i=fi[u];i;i=ne[i])
			{
				int v=to[i];
				if(c[i]&&dis[v]>dis[u]+w[i])
				{
					dis[v]=dis[u]+w[i];
					pre[v]=u,pot[v]=i^1;
					f[v]=min(c[i],f[u]);
					if(!inq[v])q.push(v),inq[v]=1;
				}
			}
		}
		return dis[T]!=inf;
	}
	inline pair<int,int> dinic()
	{
		int cost=0,F=0;
		while(spfa())
		{
			int now=T,flow=f[T];F+=flow;
			while(now!=S)
			{
				cost+=w[pot[now]^1]*flow;
				c[pot[now]]+=flow;
				c[pot[now]^1]-=flow;
				now=pre[now];
			}
			for(int u=1;u<=m;++u)
				for(int i=fi[id[u]];i;i=ne[i])
				{
					int v=to[i];if(v!=T)continue;
					if(c[i])continue;
					adde(u,::now[u]+1);break;
				}
		}
		return make_pair(F,cost);
	}
}
using namespace Flow;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",p+i),sum+=p[i];
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			scanf("%d",&t[j][i]);
	S=1,T=2;
	for(int i=1;i<=n;++i)add(S,i+2,p[i],0);nn=n+2;
	for(int i=1;i<=m;++i)adde(i,1);
	printf("%d\n",dinic().second);
	return 0;
}

[SCOI2012] strange games

solution

Black and white dyeing. Suppose there are \ (cb \) in the black grid, and the sum of weights is \ (sb \), and there are \ (cw \) in the white grid, and the sum of weights is \ (sw \). Each operation must be black and white, with \ (1 \) added to each weight.

Assuming that the final same number is \ (X \), there is \ (sb SW = X (CB CW) \)

\(CB CW \ not = 0 \) if and only if \ (n,m \) are odd. At this point, you can calculate the value of \ (X \), and then check the maximum flow casually.

Otherwise, at least one of \ (n,m \) is even. At this time, if \ (X \) is feasible, then \ (X+1 \) must also be feasible. So the binary answer is to use the maximum flow \ (check \).

\(check \) is similar to the bipartite graph matching process. Finally, judge whether the flow is full.

view code
const int fx[]={0,0,1,-1},fy[]={1,-1,0,0};
int n,m,mp[P][P];ll sb,sw,mx;
inline bool ok(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
inline int id(int x,int y){return (x-1)*m+y;}
inline bool ck(ll x)
{
	clear();ll sum=0;
	S=n*m+1,T=S+1;nn=T;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
		{
			if(!((i+j)&1)){add(id(i,j),T,x-mp[i][j]);continue;}
			add(S,id(i,j),x-mp[i][j]);sum+=x-mp[i][j];
			for(int k=0;k<4;++k)
			{
				int x=i+fx[k],y=j+fy[k];
				if(ok(x,y))add(id(i,j),id(x,y),inf);
			}
		}
	ll ret=dinic();
	return ret==sum;
}
int main()
{
	int t;scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);mx=sb=sw=0;
		for(int i=1;i<=n;++i)
			for(int j=1;j<=m;++j)
			{
				scanf("%d",&mp[i][j]);
				((i+j)&1)?sb+=mp[i][j]:sw+=mp[i][j];
				mx=max(mx,0ll+mp[i][j]);
			}
		if((n*m)&1)
		{
			ll ans=sw-sb;
			if(ans<mx||!ck(ans))puts("-1");
			else printf("%lld\n",(1ll*n*m*ans-sw-sb)/2);
			continue;
		}
		if(sb!=sw){puts("-1");continue;}
		ll l=mx-1,r=5e9;
		while(l+1<r)
		{
			ll mid=(l+r)>>1;
			ck(mid)?r=mid:l=mid;
		}
		printf("%lld\n",(1ll*n*m*r-sw-sb)/2);
	}
	return 0;
}

80 people travel around the world

solution

Consider splitting each country into input points and output points, and connecting edges with a capacity of \ (v_i \).

However, this does not guarantee that each country passes through \ (v_i \) times, so the cost is set to \ (\ infty \), which can induce it to run out of capacity.

Then, for the ticket value from \ (i \) to \ (j \) is \ (w \), we connect the outgoing point of \ (i \) and the incoming point of \ (j \), with a capacity of \ (\ infty \) and a cost of \ (W \).

Build a point to connect edges to all entry points. The capacity is \ (\ infty \) and the cost is \ (0 \), which means that you can start from any position. The source point connects an edge with a capacity of \ (m \) to this point.

All outgoing points are connected to sink points, with a capacity of \ (\ infty \) and a cost of \ (0 \), which means that it can start and end from any position.

Assuming that the answer to the last minimum cost maximum flow is \ (ans \), the final answer is \ (ans+sum\times \infty \), where \ (sum=\sum v_i \)

code

view code
int n,m,x,sum;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		scanf("%d",&x),add(i,i+n,x,-inf),sum+=x;
	nn=n*2;
	for(int i=1;i<n;++i)
		for(int j=i+1;j<=n;++j)
		{
			scanf("%d",&x);
			if(x<0)continue;
			add(i+n,j,_inf,x);
		}
	S=++nn;
	for(int i=1;i<=n;++i)add(S,i,_inf,0);
	add(++nn,S,m,0);S=nn;
	T=++nn;
	for(int i=1;i<=n;++i)add(i+n,T,_inf,0);
	printf("%lld\n",dinic().second+inf*sum);
	return 0;
}

[show2003] eat beans

solution

First of all, it is useless that the paths cannot intersect, because if they intersect, they can turn around respectively at the intersection point, which will not affect the final answer.

There is an obvious way to build a map: dismantle each Doudou point and connect two sides from the incoming point to the outgoing point. One flow is \ (1 \) and the cost is \ (1 \), the other flow is \ (\ infty \) and the cost is \ (0 \), which means that this point can be accounted for many times but only once. Then the legal point-to-point connection between point pairs can be made. Finally, run the maximum cost and maximum flow.

This will time out directly because there are too many edges connected. Consider optimization. Note that if \ (i\rightarrow j,j\rightarrow k \), the edge of \ (i\rightarrow k \) is unnecessary. So you can arrange the order and then make a wave at will. (the number of connected edges is not minimized here, but it is slightly better than violent edges. It should or may be stuck)

code

view code
struct pt{int x,y;}p[P];
inline bool operator<(const pt&x,const pt&y){return x.x!=y.x?x.x<y.x:x.y<y.y;}
int n;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y);
	sort(p+1,p+n+1);
	nn=n*2;
	for(int i=1;i<=n;++i)add(i,i+n,1,1),add(i,i+n,inf,0);
	S=++nn;
	for(int i=1;i<=n;++i)add(S,i,inf,0);
	add(++nn,S,2,0);S=nn;
	T=++nn;
	for(int i=1;i<=n;++i)add(i+n,T,inf,0);
	for(int i=1;i<=n;++i)
	{
		int now=inf;
		for(int j=1;j<=n;++j)
		{
			if(i==j||p[j].x<p[i].x||p[j].y<p[i].y)continue;
			if(now>=p[j].y)add(i+n,j,inf,0),now=p[j].y;
		}
	}
	printf("%d\n",dinic().second);
	return 0;
}

Topics: network-flows