[network flow question 24] Mars Exploration

Cost flow

General idea of the topic

Here is a map of $P \times Q $. There are three kinds of terrain on it:

  • $mp[i][j]=0 $, indicating that the $I $row and $j $column of the map are flat terrain, which can be passed at will.

  • $mp[i][j]=1 $, indicating that the $I $row and $j $column of the map are obstacle terrain and cannot be passed.

  • $mp[i][j]=2 $, indicating that the $I $row and $j $column of the map are rock samples, which can be passed at will, but only one pass can be recorded, indicating collection.

Now, there are $n $exploration vehicles. They can only go east or south. You need to get as many rock samples as possible while ensuring that they can reach the destination (Note: if the exploration vehicle does not reach the destination, the rock samples collected by it will be discarded)

Topic analysis

Obviously, this problem can be solved with the maximum cost and maximum flow.

Consider how to create a drawing:

  • For each $2 $node, it can only be collected once. We naturally thought of splitting points to solve it. Break $i node into $i node_ 1 $and $i_2 $, the operation of collecting rock samples once is actually in $i_1 $and $i_ There is even a side with a traffic of $1 and a cost of $1 between $2. However, after being collected, the $2 $node can be processed countless times. The corresponding edge construction is to build another edge with positive infinite traffic and $0 $cost.

  • For every $1 $node, it is obvious that no point will connect edges to it, and he will not connect edges to any point.

  • For each node with a value of $0 $, in fact, in theory, we should not need to dismantle the point, because the point weight of each node is positive infinity except $1 $. It is not necessary to convert the point weight into edge weight to limit the flow, but for convenience, we still divide it into two points, and connect them with an edge with a value of positive infinity and a cost of $0 $.

For details, please refer to the following drawing code:

//Mapping (summary points: 2*p*q, source point: 0, sink point: 2*p*q+1)
//Take all points apart
//Connection between disassembly points: 0 - > 0, flow INF, cost 0,1 - > 1, flow 1, cost 1 
for(register int i=1;i<=p;i++){
	for(register int j=1;j<=q;j++){
		if(mp[i][j]==1) continue; //No point is connected with the obstacle
		int u=Get_id(i,j),v; //u represents the current node number and v represents the target node number 
		//Set the disassembly point of node i as I ' 
		//Outward edge: u '- > V
		for(register int k=0;k<=1;k++){
			int nx=i+dx[k],ny=j+dy[k];
			if(nx>p||ny>q) continue; //Not beyond the boundary
			if(mp[nx][ny]==1) continue; //obstacle 
			v=Get_id(nx,ny);
			Add(u+p*q,v,INF,0),Add(v,u+p*q,0,0);
		}
		//Connect yourself: U - > u ' 
		//For rock specimens, two sets of edges are established. The first set of current limiting 1 that contributes to the answer indicates that it can only be collected once
		//The second group shows that rock specimens can arrive at any time like ordinary ground 
		if(mp[i][j]==2) Add(u,u+p*q,1,1),Add(u+p*q,u,0,-1); //The current node is rock specimen 
			//Any point outside the obstacle can be reached at will 
		Add(u,u+p*q,INF,0),Add(u+p*q,u,0,0);
	}
}

How to print paths

For the path, we only need to run $DFS $from $(1,1) $on the residual graph, find the edges flowing through and print them

Reference codes are as follows:

inline void DFS(int x,int y,int u,int k)
{
	int kx,ky,mov;
	for(register int i=first[u];i!=-1;i=nex[i]){
		int to=v[i];
		if(to==s||to==t||to==u-p*q||!w[i^1]) continue;
		w[i^1]--; //The number of passes --, known as 0, indicates that all the detection vehicles passing on the side have been considered
		if(to>p*q) { DFS(x,y,to,k); return; } //If i 'is reached, it is the dismantling point connecting other points 
		if(to==Get_id(x,y)+1) kx=x,ky=y+1,mov=1; //Determine which point to go 
		else kx=x+1,ky=y,mov=0;
		printf("%d %d\n",k,mov);
		DFS(kx,ky,to+p*q,k); //recursion 
		return;
	}
}

be careful

The input order of $p$and $q$in this question, the column to be input first, and then the row to be input, I found it after adjusting it for a year. I was really impressed.

CODE

#include <bits/stdc++.h>
using namespace std;
const int N=1e2,INF=0x3f3f3f3f;
const int dx[2]={0,1},dy[2]={1,0};
int n,p,q;
int s,t,ans,maxf;
int mp[N][N];
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
int tot=-1,v[N*N*N],w[N*N*N],pay[N*N*N],nex[N*N*N],first[2*N*N];
inline void Add(int x,int y,int z,int c)
{
	nex[++tot]=first[x];
	first[x]=tot;
	v[tot]=y,w[tot]=z,pay[tot]=c;
}
inline int Get_id(int x,int y) { return (x-1)*q+y; }
bool vis[2*N*N];
//Min[i] represents the one with the smallest side flow passing through the arrival point I 
int dis[2*N*N],pre[2*N*N],Min[2*N*N];
inline bool SPFA()
{
	for(register int i=s;i<=t;i++) vis[i]=false;
	for(register int i=s;i<=t;i++) dis[i]=-INF;
	queue<int> q; q.push(s);
	vis[s]=true,dis[s]=0,Min[s]=INF;
	while(!q.empty()){
		int now=q.front(); q.pop();
		vis[now]=false;
		for(register int i=first[now];i!=-1;i=nex[i]){
			int to=v[i];
			if(!w[i]) continue; //No flow 
			if(dis[to]<dis[now]+pay[i]){ //Longest path update 
				dis[to]=dis[now]+pay[i];
				Min[to]=min(Min[now],w[i]);
				pre[to]=i;
				if(!vis[to]) q.push(to),vis[to]=true;
			}
		}
	}
	return dis[t]!=-INF;
}
inline void EK()
{
	while(SPFA()){
		maxf+=Min[t];
		int temp=t,i;
		while(temp!=s){
			i=pre[temp];
			w[i]-=Min[t]; 
			w[i^1]+=Min[t];
			temp=v[i^1];
		}
	}
}
inline void DFS(int x,int y,int u,int k)
{
	int kx,ky,mov;
	for(register int i=first[u];i!=-1;i=nex[i]){
		int to=v[i];
		if(to==s||to==t||to==u-p*q||!w[i^1]) continue;
		w[i^1]--;
		if(to>p*q) { DFS(x,y,to,k); return; } //If i 'is reached, it is the dismantling point connecting other points 
		if(to==Get_id(x,y)+1) kx=x,ky=y+1,mov=1; //Determine which point to go 
		else kx=x+1,ky=y,mov=0;
		printf("%d %d\n",k,mov);
		DFS(kx,ky,to+p*q,k); //recursion 
		return;
	}
}
int main()
{
	memset(first,-1,sizeof(first));
	n=read(),q=read(),p=read();
	for(register int i=1;i<=p;i++)
		for(register int j=1;j<=q;j++)  mp[i][j]=read();
	s=0,t=2*p*q+1;
	//Mapping (summary points: 2*p*q, source point: 0, sink point: 2*p*q+1)
	//Take all points apart
	//Connection between disassembly points: 0 - > 0, flow INF, cost 0,1 - > 1, flow 1, cost 1 
	for(register int i=1;i<=p;i++){
		for(register int j=1;j<=q;j++){
			if(mp[i][j]==1) continue; //No point is connected with the obstacle
			int u=Get_id(i,j),v; //u represents the current node number and v represents the target node number 
			//Set the disassembly point of node i as I ' 
			//Outward edge: u '- > V
			for(register int k=0;k<=1;k++){
				int nx=i+dx[k],ny=j+dy[k];
				if(nx>p||ny>q) continue; //Not beyond the boundary
				if(mp[nx][ny]==1) continue; //obstacle 
				v=Get_id(nx,ny);
				Add(u+p*q,v,INF,0),Add(v,u+p*q,0,0);
			}
			//Connect yourself: U - > u ' 
			//For rock specimens, two sets of edges are established. The first set of current limiting 1 that contributes to the answer indicates that it can only be collected once
			//The second group shows that rock specimens can arrive at any time like ordinary ground 
			if(mp[i][j]==2) Add(u,u+p*q,1,1),Add(u+p*q,u,0,-1); //The current node is rock specimen 
			//Any point outside the obstacle can be reached at will 
			Add(u,u+p*q,INF,0),Add(u+p*q,u,0,0);
		}
	}
	if(mp[1][1]!=1) Add(s,1,n,0),Add(1,s,0,0);
	if(mp[p][q]!=1) Add(Get_id(p,q)+p*q,t,n,0),Add(t,Get_id(p,q)+p*q,0,0);
	EK();
	for(register int i=1;i<=maxf;i++) DFS(1,1,1,i);
	return 0;
}

Tags: network-flows

Posted by TheLoveableMonty on Mon, 18 Apr 2022 07:02:08 +0930