Network Flow Template
The author uses Dinic algorithm for maximum flow and SPFA algorithm for cost flow. In the network flow problem, if the maximum flow of a graph needs to be calculated repeatedly, the current feasible flow should be cleared before the maximum flow is calculated each time. In the cost flow problem, when the maximum cost flow is obtained, all side costs can be taken into account and transformed into the minimum cost flow problem equivalently. The Title Description of the original topic is brief, because there is no SPJ, all the inquiries about output schemes are ignored, and when necessary, they are transformed into decisive questions. The code is as follows:
#include<string.h>
#define MAX_E (0xFFFFF)
#define MAX_V (0xFFFF)
#define INF (0x7FFFFFFF)
#define Min_Integer(a,b) \
({ \
int __tmp_a=(a),__tmp_b=(b); \
__tmp_a<__tmp_b?__tmp_a:__tmp_b; \
})
struct MaxFlow
{
int cur[MAX_V],dist[MAX_V],e,que[MAX_V],s,t,v,vertex[MAX_V];
struct MaxFlow_Edge
{
int cap,flow,next,to;
}edge[MAX_E];
MaxFlow()
{
e=0;
memset(vertex,-1,sizeof(vertex));
}
void AddSingleEdge(int eg,int fr,int to,int cp)
{
edge[eg].to=to,edge[eg].cap=cp,edge[eg].flow=0;
edge[eg].next=vertex[fr],vertex[fr]=eg;
}
void AddEdge(int u,int v,int c)
{
AddSingleEdge(e<<1,u,v,c);
AddSingleEdge(e<<1^1,v,u,0);
e++;
}
bool Dinic_Bfs()
{
int QueueTop=0;
memset(dist,-1,sizeof(dist));
dist[s]=0;
que[QueueTop++]=s;
for(int i=0;i<QueueTop;i++)
for(int j=vertex[que[i]];j>-1;j=edge[j].next)
if(dist[edge[j].to]==-1&&edge[j].cap>edge[j].flow)
dist[edge[j].to]=dist[que[i]]+1,
que[QueueTop++]=edge[j].to;
return dist[t]>-1;
}
int Dinic_Dfs(int now,int flow)
{
if(now==t)
return flow;
int f,sum=0;
for(;cur[now]>-1&&flow>0;cur[now]=edge[cur[now]].next)
if(dist[now]+1==dist[edge[cur[now]].to]
&&(f=Dinic_Dfs(edge[cur[now]].to,Min_Integer(flow,edge[cur[now]].cap-edge[cur[now]].flow)))>0)
edge[cur[now]].flow+=f,
edge[cur[now]^1].flow-=f,
sum+=f,
flow-=f;
return sum;
}
int Solve()
{
int ans=0;
while(Dinic_Bfs())
{
for(int i=1;i<=v;i++)
cur[i]=vertex[i];
ans+=Dinic_Dfs(s,INF);
}
return ans;
}
};
struct MinCost
{
bool inq[MAX_V];
int dist[MAX_V],e,flow[MAX_V],prev[MAX_V],que[MAX_V],s,t,v,vertex[MAX_V];
struct MinCost_Edge
{
int cap,cost,flow,from,next,to;
}edge[MAX_E];
MinCost()
{
e=0;
memset(vertex,-1,sizeof(vertex));
}
void AddSingleEdge(int eg,int fr,int to,int cp,int ct)
{
edge[eg].from=fr,edge[eg].to=to,edge[eg].cap=cp,edge[eg].flow=0,edge[eg].cost=ct;
edge[eg].next=vertex[fr],vertex[fr]=eg;
}
void AddEdge(int u,int v,int c,int t)
{
AddSingleEdge(e<<1,u,v,c,t);
AddSingleEdge(e<<1^1,v,u,0,-t);
e++;
}
void ClearEdgeFlow()
{
for(int i=0;i<e<<1;i++)
edge[i].flow=0;
}
void NegateEdgeCost()
{
for(int i=0;i<e<<1;i++)
edge[i].cost=-edge[i].cost;
}
bool Bfs(int &mf,int &mc)
{
int QueueTop=0;
for(int i=1;i<=v;i++)
dist[i]=INF,flow[i]=0,inq[i]=false,prev[i]=-1;
dist[s]=0;
flow[s]=INF;
inq[s]=false;
que[QueueTop++]=s;
for(int i=0;i<QueueTop;i++)
{
inq[que[i]]=false;
for(int j=vertex[que[i]];j>-1;j=edge[j].next)
if(edge[j].cap>edge[j].flow&&dist[que[i]]+edge[j].cost<dist[edge[j].to])
{
dist[edge[j].to]=dist[que[i]]+edge[j].cost;
flow[edge[j].to]=Min_Integer(flow[que[i]],edge[j].cap-edge[j].flow);
prev[edge[j].to]=j;
if(!inq[edge[j].to])
inq[edge[j].to]=true,
que[QueueTop++]=edge[j].to;
}
}
if(dist[t]==INF)
return false;
for(int i=t;i!=s;i=edge[prev[i]].from)
edge[prev[i]].flow+=flow[t],
edge[prev[i]^1].flow-=flow[t];
mf+=flow[t],mc+=dist[t]*flow[t];
return true;
}
void Solve(int &mf,int &mc)
{
while(Bfs(mf,mc));
}
};
Question 1 Pilot Matching Scheme
Maximum flow. If the pilots are regarded as points and the pairable pilots are regarded as edges, the original title is the maximum matching problem of bipartite graphs. The drawings are as follows:
1. For each pair of matchable British and foreign pilots, the flow INF is connected from the British pilots'point to the foreign pilots' point.
2. Build the total source point S, from S to each foreign pilot point connected with the side of flow 1;
3. Build a summary point T, from each British pilot point to the side of T-link flow 1.
The maximum flow value of the graph is the answer. The code is as follows:
#include<stdio.h>
MaxFlow net;
int main()
{
int m,n,u,v;
scanf("%d %d",&m,&n);
while(true)
{
scanf("%d %d",&u,&v);
if(u==-1&&v==-1)
break;
net.AddEdge(u,v,INF);
}
net.s=n+1,net.t=net.v=n+2;
for(int i=1;i<=m;i++)
net.AddEdge(net.s,i,1);
for(int i=m+1;i<=n;i++)
net.AddEdge(i,net.t,1);
printf("%d",net.Solve());
return 0;
}
Question 2: Space Flight Planning
Minimum cut. The drawings are as follows:
1. Build the total source point S, and connect the flow rate from S to each experimental point as the experimental cost side.
2. Connect the flow INF side from each experimental point to the instrument point needed for the experiment.
3. Build a summary point T, from each instrument point to T flow as the cost side of the instrument.
The answer is to subtract the maximum flow from the total cost of all experiments. The code is as follows:
#include<stdio.h>
MaxFlow net;
int main()
{
char t;
int c,m,n,s=0;
scanf("%d %d",&m,&n);
net.s=m+n+1,net.t=net.v=net.s+1;
for(int i=1;i<=m;i++)
{
scanf("%d",&c);
s+=c;
net.AddEdge(net.s,i,c);
while((t=getchar())!='\n')
scanf("%d",&c),
net.AddEdge(i,m+c,INF);
}
for(int i=1;i<=n;i++)
scanf("%d",&c),
net.AddEdge(m+i,net.t,c);
printf("%d",s-net.Solve());
return 0;
}
Problem 3 Minimum Path Covering Problem
Maximum flow. In a path coverage scheme for directed acyclic graphs, the entry and exit edges of each point are not larger than one. The original problem is transformed into the maximum matching problem of bipartite graphs by splitting points so that as many entries and exit points as possible correspond to each other. The drawings are as follows:
1. Disassemble the points in the original drawing into entry points and exit points.
2. For each directed edge in the original graph, the flow INF edge is connected from the starting point of the edge to the entry point of the end point of the edge.
3. Build the total source point S and connect the flow 1 edge from S to the entry point of each point in the original map.
4. Build a summary point T, from the point of departure of each point in the original map to the side of T connected with flow 1.
The answer is to subtract the maximum flow from the number of nodes in the original graph. The code is as follows:
#include<stdio.h>
MaxFlow net;
int main()
{
int m,n,u,v;
scanf("%d %d",&n,&m);
while(m--)
scanf("%d %d",&u,&v),
net.AddEdge(u,n+v,INF);
net.s=(n<<1)+1,net.t=net.v=net.s+1;
for(int i=1;i<=n;i++)
net.AddEdge(net.s,i,1),
net.AddEdge(i+n,net.t,1);
printf("%d",n-net.Solve());
return 0;
}
Question 4 Magic Ball
Maximum flow. From small to large enumeration of the number of releasable balls, the original topic is transformed into a decisive problem. If the ball is regarded as a point and the adjacent balls are regarded as directed edges from numbered balls to numbered balls, the original problem is transformed into the minimum path coverage problem. The drawings are as follows:
1. Disassembly point, each sphere is divided into entry point and exit point.
2. For each pair of adjacent balls, the flow INF is connected from the exit point of the numbered balls to the entry point of the numbered balls.
3. Construct the total source point S, connecting the inflow point from S to the inflow point of each sphere point with the side of flow rate 1;
4. Build the convergence point T, from the point of departure of each sphere to the side of T connected with flow 1.
The answer is the maximum number of spheres that make the maximum flow of the graph not larger than the number of columns. The code is as follows:
#include<stdio.h>
MaxFlow net;
int main()
{
int m=0,n,s=0;
scanf("%d",&n);
net.s=1,net.t=net.v=2;
do
{
++m,net.v+=2;
net.AddEdge(net.s,m<<1^1,1);
net.AddEdge(m+1<<1,net.t,1);
for(int i=1;i*i<m<<1;i++)
if(i*i>m)
net.AddEdge(i*i-m<<1^1,m+1<<1,INF);
s+=net.Solve();
}while(m-s<=n);
printf("%d",--m);
return 0;
}
Question 5 Round Table Question
Maximum flow. Consider units and tables as points, and representatives as flows. The drawings are as follows:
1. Construct the total source point S and connect the flow from S to each unit point as the side of the unit representative number.
2. Build a summary point T, from each table point to the T-line flow for the side of the table representative number;
3. For each unit point and each table point, from the unit point to the side of the table point connected with flow 1.
Whether the maximum flow of the graph is equal to the total number of units represented is the answer. The code is as follows:
#include<stdio.h>
MaxFlow net;
int main()
{
int c,m,n,s=0;
scanf("%d %d",&m,&n);
net.s=m+n+1,net.t=net.v=net.s+1;
for(int i=1;i<=m;i++)
scanf("%d",&c),s+=c,
net.AddEdge(net.s,i,c);
for(int i=m+1;i<=m+n;i++)
scanf("%d",&c),
net.AddEdge(i,net.t,c);
for(int i=1;i<=m;i++)
for(int j=m+1;j<=m+n;j++)
net.AddEdge(i,j,1);
printf("%d",net.Solve()==s?1:0);
return 0;
}
Question 6 The Problem of Maximum Incremental Subsequence
Maximum flow. Firstly, the length of the longest incremental subsequence ending with x[i] is obtained by dynamic programming, which is recorded as f[i], and the maximum value of F [1.. N] is the first answer. The drawings are as follows:
1. Disassembly point, each element point in the sequence is divided into entry point and exit point. For each pair of entry point and exit point, flow 1 is connected from entry point to exit point.
2. Construct the total source point S and connect the flow 1 side from S to the entry point of each element point.
3. Build a summary point T, from the point of departure of each element point to the side of T connected with flow 1;
4. For each pair of elements x[i] and x[j], it is advisable to set I > J. If and only I F x[i] > x[j] and f[i] = f[j] + 1, the flow from the exit point of element x[j] to the entry point of element x[i] is connected to the side of flow 1.
The maximum flow value of the graph is the second answer. On the basis of this map, the following drawings are constructed:
1. Set the flow rate from entry point to exit point of element x[1] as INF;
2. Set the flow rate from entry point to exit point of element x[n] as INF.
The maximum flow value of the graph is the third answer. The original data is incorrect and the longest non-descending subsequence is obtained. The code is as follows:
#include<stdio.h>
MaxFlow net;
int f[1005],x[1005];
int main()
{
int m,n,s=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x[i]);
f[i]=1;
for(int j=1;j<i;j++)
if(x[i]>=x[j]&&f[i]<f[j]+1)
f[i]=f[j]+1;
if(f[i]>s)
s=f[i];
}
printf("%d\n",s);
net.s=n<<1^1,net.t=net.v=net.s+1;
for(int i=1;i<=n;i++)
{
net.AddEdge(i,i+n,1);
if(f[i]==1)
net.AddEdge(net.s,i,1);
if(f[i]==s)
net.AddEdge(i+n,net.t,1);
for(int j=1;j<i;j++)
if(x[i]>=x[j]&&f[i]==f[j]+1)
net.AddEdge(j+n,i,1);
}
printf("%d\n",m=net.Solve());
net.AddEdge(net.s,1,INF);
if(f[n]==s)
net.AddEdge(n<<1,net.t,INF);
net.AddEdge(1,1+n,INF);
net.AddEdge(n,n<<1,INF);
printf("%d",m+=net.Solve());
return 0;
}
Question Bank of the seventh question
Maximum flow. Consider the types and questions as points. The drawings are as follows:
1. Construct the total source point S, from S to each type of point, and connect the flow to the side of the number of questions needed for that type.
2. Build a summary point T, from each test point to the side of T-connected flow 1;
3. For each type of point to which each test point belongs, connect the flow 1 side from that type point to the test point.
The answer is whether the maximum flow of the graph is equal to the total number of questions required for all types. The code is as follows:
#include<stdio.h>
MaxFlow net;
int main()
{
int c,k,n,p,s=0;
scanf("%d %d",&k,&n);
net.s=k+n+1,net.t=net.v=net.s+1;
for(int i=1;i<=k;i++)
scanf("%d",&c),s+=c,
net.AddEdge(net.s,i,c);
for(int i=k+1;i<=k+n;i++)
{
net.AddEdge(i,net.t,1);
scanf("%d",&p);
while(p--)
scanf("%d",&c),
net.AddEdge(c,i,1);
}
printf("%s",net.Solve()==s?"1":"No Solution!");
return 0;
}
Problem 8 Robot Path Planning
Cost flow. It is difficult for the author to solve this problem because of his lack of knowledge.
Question 9: Number of squares
Minimum cut. The drawings are as follows:
1. The original picture is dyed black and white so that it is not adjacent to the lattice.
2. Construct the total source point S and connect the flow from S to each black grid point as the edge of the grid value.
3. For each pair of adjacent black and white grid points, the flow INF edge is connected from black to white grid points.
4. Build the convergence point T, and the flow from each white grid point to T is the edge of the lattice value.
The answer is to subtract the total value of all lattices from the maximum flow of the graph. The code is as follows:
#include<stdio.h>
MaxFlow net;
int main()
{
int c,m,n,s=0;
scanf("%d %d",&m,&n);
net.s=m*n+1,net.t=net.v=net.s+1;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&c);
s+=c;
if((i+j&1)==0)
{
net.AddEdge(net.s,i*n+j+1,c);
if(i>0)
net.AddEdge(i*n+j+1,(i-1)*n+j+1,INF);
if(j>0)
net.AddEdge(i*n+j+1,i*n+j,INF);
if(i+1<m)
net.AddEdge(i*n+j+1,(i+1)*n+j+1,INF);
if(j+1<n)
net.AddEdge(i*n+j+1,i*n+j+2,INF);
}
else
net.AddEdge(i*n+j+1,net.t,c);
}
printf("%d",s-net.Solve());
return 0;
}
Topic 10 Napkin Planning
Cost flow. Think of everyday as a point. The drawings are as follows:
1. Disassemble points, divide them into entry points and exit points every day.
2. Build the total source point S, and the flow from S to the entry point of each day is the number of napkins needed for that day at the cost of 0.
3. Build a summary point T, from the point of departure to the point of continuous flow of T for the number of napkins needed for that day, the cost of 0 side;
4. Flow INF from S to the point of departure every day at the cost of a new napkin.
5. From the entry point of each day to the entry point of the day after, the flow of INF is connected to the side of cost 0.
6. From the entry point of each day to the exit point after the number of days needed for quick washing, the cost is the side of the cost of a napkin for quick washing.
7. From the entry point of every day to the outlet point after the days needed for slow washing, the cost is the side of a napkin for slow washing.
The minimum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
MinCost net;
int main()
{
int f,m,N,n,p,r,s;
scanf("%d %d %d %d %d %d",&N,&p,&m,&f,&n,&s);
net.s=N<<1^1,net.t=net.v=net.s+1;
for(int i=1;i<=N;i++)
{
scanf("%d",&r);
net.AddEdge(net.s,i,r,0);
net.AddEdge(i+N,net.t,r,0);
net.AddEdge(net.s,i+N,INF,p);
if(i<N)
net.AddEdge(i,i+1,INF,0);
if(i+m<=N)
net.AddEdge(i,i+m+N,INF,f);
if(i+n<=N)
net.AddEdge(i,i+n+N,INF,s);
}
N=r=0;
net.Solve(N,r);
printf("%d",r);
return 0;
}
Question 11 Air Routes
Cost flow. The original theme is to find two disjoint paths from the westernmost city to the easternmost city, so that the most cities passed through, the city as a point. The drawings are as follows:
1. Disassembly point, each city point is divided into entry point and exit point. For each pair of entry point and exit point, flow rate from entry point to exit point is 1 and cost is 1.
2. From the entry point of the westernmost city point to the exit point, the flow rate is 1 and the cost is 0.
3. From the entry point of the easternmost city point to the exit point, the flow rate is 1 and the cost is 0.
4. For the two cities connected by each route, the inflow INF is connected from the exit point of the West City point to the entry point of the east city point, and the cost is 0.
The origin point is the entry point of the westernmost city point, and the confluence point is the exit point of the easternmost city point. The maximum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
MinCost net;
char city[1005][20],city1[20],city2[20];
int main()
{
int c1,c2,n,v;
scanf("%d %d\n",&n,&v);
net.s=1,net.t=net.v=n<<1;
net.AddEdge(1,n+1,1,0);
net.AddEdge(n,n<<1,1,0);
for(int i=1;i<=n;i++)
gets(city[i]),
net.AddEdge(i,i+n,1,-1);
while(v--)
{
scanf("%s %s",city1,city2);
c1=c2=0;
for(int i=1;i<=n&&c1==0;i++)
if(strcmp(city[i],city1)==0)
c1=i;
for(int i=1;i<=n&&c2==0;i++)
if(strcmp(city[i],city2)==0)
c2=i;
if(c1<c2)
net.AddEdge(c1+n,c2,INF,0);
else
net.AddEdge(c2+n,c1,INF,0);
}
n=v=0;
net.Solve(n,v);
if(n==2)
printf("%d",-v);
else
printf("No Solution!");
return 0;
}
Twelfth Issue: Software Patches
Shortest path. The current set of errors is recorded as a state, the binary representation is used as a point, the patch represents the transition between states, and the edge is regarded as the edge. The edge weight is time-consuming for the patch, and the implicit mapping is constructed. The shortest path from all error states to error-free States is the answer. The code is as follows:
#include<stdio.h>
bool inq[1048580];
char str[25];
int dist[1048580],que[1048580];
struct EDGE
{
int b1,b2,cost,f1,f2;
}patch[105];
int main()
{
int m,n,quetop=0;
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d %s",&patch[i].cost,str);
patch[i].b1=patch[i].b2=patch[i].f1=patch[i].f2=0;
for(int j=0;str[j];j++)
if(str[j]=='+')
patch[i].b1|=1<<j;
else if(str[j]=='-')
patch[i].b2|=1<<j;
scanf("%s",str);
for(int j=0;str[j];j++)
if(str[j]=='-')
patch[i].f1|=1<<j;
else if(str[j]=='+')
patch[i].f2|=1<<j;
}
for(int i=0;i<1<<n;i++)
dist[i]=INF,inq[i]=false;
dist[(1<<n)-1]=0,inq[(1<<n)-1]=true,que[quetop++]=(1<<n)-1;
for(int i=0;i<quetop;i++)
{
inq[que[i]]=false;
for(int j=0;j<m;j++)
if((que[i]&patch[j].b1)==patch[j].b1&&(que[i]&patch[j].b2)==0
&&dist[que[i]]+patch[j].cost<dist[que[i]&~patch[j].f1|patch[j].f2])
{
dist[que[i]&~patch[j].f1|patch[j].f2]=dist[que[i]]+patch[j].cost;
if(!inq[que[i]&~patch[j].f1|patch[j].f2])
inq[que[i]&~patch[j].f1|patch[j].f2]=true,
que[quetop++]=que[i]&~patch[j].f1|patch[j].f2;
}
}
printf("%d",dist[0]<INF?dist[0]:0);
return 0;
}
Question 13 Interstellar Transfer
Maximum flow. From small to large enumeration of unit time, the original topic is transformed into a decisive problem. Think of each space station per unit time as a point and the spaceship route as a side. The drawings are as follows:
1. For each space station per unit time, from that point to the next unit time, the space station is connected to the side of the INF flow.
2. For each spacecraft, from the space station where the unit time is located to the space station where the next unit time is located, the continuous flow is the side of the spacecraft that can accommodate the number of people.
The point of origin is the earth and the point of confluence is the moon. The answer is to make the maximum flow not less than the minimum unit time of the number of people to be transported. The code is as follows:
#include<stdio.h>
MaxFlow net;
struct SHIP
{
int hpi,r,si[25];
}pi[15];
int main()
{
int k,m,n,t;
scanf("%d %d %d",&n,&m,&k);
for(int i=0;i<m;i++)
{
scanf("%d %d",&pi[i].hpi,&pi[i].r);
for(int j=0;j<pi[i].r;j++)
scanf("%d",&pi[i].si[j]);
pi[i].si[pi[i].r]=pi[i].si[0];
}
net.s=2,net.t=1,net.v=n+2;
for(t=0;t<=50&&k>0;net.v+=n,k-=net.Solve(),t++)
{
for(int i=3;i<=n+2;i++)
net.AddEdge(i+n*t,i+n*(t+1),INF);
for(int i=0;i<m;i++)
net.AddEdge(pi[i].si[t%pi[i].r]+(pi[i].si[t%pi[i].r]>0)*n*t+2,
pi[i].si[t%pi[i].r+1]+(pi[i].si[t%pi[i].r+1]>0)*n*(t+1)+2,pi[i].hpi);
}
printf("%d",k<=0?t:0);
return 0;
}
Question 14 Rescue of Isles
Shortest path. Hierarchical map, the current holding of the key is also considered as a one-dimensional state, the shortest path can be found. The code is as follows:
#include<stdio.h>
bool inq[12][12][1025];
int dist[12][12][1025];
struct MAP_UNIT
{
int east,key,north,south,west;
}map[12][12];
struct QUEUE_UNIT
{
int key,x,y;
}que[102405];
#define BuildDoor(x,y,dir,key) \
{ \
if(map[x][y].dir>-1) \
if(key>0) \
map[x][y].dir|=1<<key-1; \
else \
map[x][y].dir=-1; \
}
#define Update(dx,dy,newkey,d) \
if(dist[que[i].x][que[i].y][que[i].key]+d<dist[que[i].x+dx][que[i].y+dy][newkey]) \
{ \
dist[que[i].x+dx][que[i].y+dy][newkey]=dist[que[i].x][que[i].y][que[i].key]+d; \
if(!inq[que[i].x+dx][que[i].y+dy][newkey]) \
inq[que[i].x+dx][que[i].y+dy][newkey]=true, \
que[quetop].x=que[i].x+dx,que[quetop].y=que[i].y+dy,que[quetop++].key=newkey; \
}
#define Move(dx,dy,dir) \
if(map[que[i].x][que[i].y].dir>=0 \
&&(map[que[i].x][que[i].y].dir&que[i].key)==map[que[i].x][que[i].y].dir) \
Update(dx,dy,que[i].key,1);
int main()
{
int g,k,m,n,p,quetop=1,x1,x2,y1,y2;
scanf("%d %d %d%d",&n,&m,&p,&k);
for(int ix=0;ix<n;ix++)
for(int iy=0;iy<m;iy++)
{
map[ix][iy].east=iy+1<m?0:-1;
map[ix][iy].south=ix+1<n?0:-1;
map[ix][iy].west=iy>0?0:-1;
map[ix][iy].north=ix>0?0:-1;
map[ix][iy].key=0;
for(int ik=0;ik<1<<p;ik++)
dist[ix][iy][ik]=INF,inq[ix][iy][ik]=false;
}
while(k--)
{
scanf("%d %d %d %d %d",&x1,&y1,&x2,&y2,&g);
--x1,--x2,--y1,--y2;
if(y1+1==y2)
{
BuildDoor(x1,y1,east,g);
BuildDoor(x2,y2,west,g);
}
else if(x1+1==x2)
{
BuildDoor(x1,y1,south,g);
BuildDoor(x2,y2,north,g);
}
else if(y1-1==y2)
{
BuildDoor(x1,y1,west,g);
BuildDoor(x2,y2,east,g);
}
else
{
BuildDoor(x1,y1,north,g);
BuildDoor(x2,y2,south,g);
}
}
scanf("%d",&k);
while(k--)
scanf("%d %d %d",&x1,&y1,&g),
map[x1-1][y1-1].key|=1<<g-1;
dist[0][0][0]=0,inq[0][0][0]=true,p=INF,que[0].key=que[0].x=que[0].y=0;
for(int i=0;i<quetop;i++)
{
inq[que[i].x][que[i].y][que[i].key]=false;
if(que[i].x==n-1&&que[i].y==m-1&&p>dist[n-1][m-1][que[i].key])
p=dist[n-1][m-1][que[i].key];
Move(0,1,east);
Move(1,0,south);
Move(0,-1,west);
Move(-1,0,north);
Update(0,0,que[i].key|map[que[i].x][que[i].y].key,0);
}
printf("%d",p<INF?p:-1);
return 0;
}
Question 15 Vehicle Refueling
Shortest path. Layer diagram, the current oil volume is also considered as a one-dimensional state, the shortest path can be found. The code is as follows:
#include<stdio.h>
bool inq[105][105][12];
int dist[105][105][12],map[105][105];
struct QUEUE_UNIT
{
int gas,x,y;
}que[1000005];
#define Update(dx,dy,newgas,d) \
if(dist[que[i].x][que[i].y][que[i].gas]+d<dist[que[i].x+dx][que[i].y+dy][newgas]) \
{ \
dist[que[i].x+dx][que[i].y+dy][newgas]=dist[que[i].x][que[i].y][que[i].gas]+d; \
if(!inq[que[i].x+dx][que[i].y+dy][newgas]) \
inq[que[i].x+dx][que[i].y+dy][newgas]=true, \
que[quetop].x=que[i].x+dx,que[quetop].y=que[i].y+dy,que[quetop++].gas=newgas; \
}
int main()
{
int a,b,c,k,n,quetop=1;
scanf("%d %d %d %d %d",&n,&k,&a,&b,&c);
for(int ix=1;ix<=n;ix++)
for(int iy=1;iy<=n;iy++)
{
scanf("%d",&map[ix][iy]);
for(int ik=0;ik<=k;ik++)
dist[ix][iy][ik]=INF,inq[ix][iy][ik]=false;
}
dist[1][1][k]=0,inq[1][1][k]=true,que[0].gas=k,que[0].x=que[0].y=1;
for(int i=0;i<quetop;i++)
{
inq[que[i].x][que[i].y][que[i].gas]=false;
if(k>que[i].gas&&map[que[i].x][que[i].y]==1)
{
Update(0,0,k,a);
continue;
}
if(k>que[i].gas)
Update(0,0,k,a+c);
if(que[i].gas>0)
{
if(que[i].y<n)
Update(0,1,que[i].gas-1,0);
if(que[i].x<n)
Update(1,0,que[i].gas-1,0);
if(que[i].y>1)
Update(0,-1,que[i].gas-1,b);
if(que[i].x>1)
Update(-1,0,que[i].gas-1,b);
}
}
a=dist[n][n][k];
while(k--)
if(a>dist[n][n][k])
a=dist[n][n][k];
printf("%d",a);
return 0;
}
Question 16 Digital Ladder Problem
Cost flow. Think of each number as a point. The drawings are as follows:
1. Disassemble points, divide each digital point into entry point and exit point. For each pair of entry point and exit point, flow 1 is connected from entry point to exit point, and the cost is the edge of the number of points.
2. Construct the total source point S, connecting the inflow point from S to the most upstream digital point with the side of flow 1 and cost 0;
3. Construct the convergence point T, from the point of departure of the lowest digital point to the side of T with flow rate of 1 and cost of 0.
4. For each non-downstream digital point, from its point of departure to its lower left point of entry, the flow 1, the cost 0 side is connected; from its point of departure to its lower right point of entry, the flow 1, the cost 0 side is connected.
The maximum cost flow of the graph is the first answer. On the basis of the graph, the flow of the edges of step 1 and step 3 is set to INF, and the maximum cost flow of the graph is the second answer. On the basis of the graph, the flow of the edge built in step 4 is set to INF, and the maximum cost flow of the graph is the third answer. The code is as follows:
#include<stdio.h>
MinCost net;
int main()
{
int ans,c,m,n;
scanf("%d %d",&m,&n);
net.s=net.v=1;
for(int i=1;i<=m;i++)
net.AddEdge(1,i<<1,1,0);
for(int i=m;i<m+n;i++)
for(int j=0;j<i;j++)
scanf("%d",&c),
net.v+=2,
net.AddEdge(net.v-1,net.v,1,-c);
net.t=++net.v;
for(int i=1;i<m+n;i++)
net.AddEdge(net.t-(i<<1)+1,net.t,1,0);
c=net.e;
for(int i=m,k=3;i+1<m+n;i++)
for(int j=0;j<i;j++,k+=2)
net.AddEdge(k,(i<<1)+k-1,1,0),
net.AddEdge(k,(i<<1)+k+1,1,0);
ans=n=0;
net.ClearEdgeFlow();
net.Solve(n,ans);
printf("%d\n",-ans);
for(int i=m;i<c;i++)
net.edge[i<<1].cap=INF;
ans=n=0;
net.ClearEdgeFlow();
net.Solve(n,ans);
printf("%d\n",-ans);
for(int i=c;i<net.e;i++)
net.edge[i<<1].cap=INF;
ans=n=0;
net.ClearEdgeFlow();
net.Solve(n,ans);
printf("%d",-ans);
return 0;
}
Issue 17 Transport
Cost flow. Think of warehouses and stores as points. The drawings are as follows:
1. Establish the total source point S, the flow from S to each warehouse is the number of goods in the warehouse, the cost of 0 side;
2. Build a summary point T. The flow from each store to T is the number of goods in the store at the cost of 0.
3. For each warehouse and store, flow INF from the warehouse to the store is charged at the corresponding cost.
The minimum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
MinCost net;
int main()
{
int c,m,n;
scanf("%d %d",&m,&n);
net.s=m+n+1,net.t=net.v=net.s+1;
for(int i=1;i<=m;i++)
scanf("%d",&c),
net.AddEdge(net.s,i,c,0);
for(int i=1;i<=n;i++)
scanf("%d",&c),
net.AddEdge(i+m,net.t,c,0);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&c),
net.AddEdge(i,j+m,INF,c);
c=m=0;
net.Solve(m,c);
printf("%d\n",c);
net.ClearEdgeFlow();
net.NegateEdgeCost();
c=m=0;
net.Solve(m,c);
printf("%d",-c);
return 0;
}
Question 18 Distribution
Cost flow. Think of people and work as points. The drawings are as follows:
1. Construct the total source point S, from S to each person connected flow 1, cost 0 side;
2. Setting up the summary point T, from each work to the side of T with a flow rate of 1 and a cost of 0;
3. For each person and each job, the cost is the side of corresponding benefit.
The maximum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
MinCost net;
int main()
{
int c,n;
scanf("%d",&n);
net.s=n<<1^1,net.t=net.v=net.s+1;
for(int i=1;i<=n;i++)
net.AddEdge(net.s,i,1,0),
net.AddEdge(i+n,net.t,1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&c),
net.AddEdge(i,j+n,INF,c);
c=n=0;
net.Solve(n,c);
printf("%d\n",c);
net.ClearEdgeFlow();
net.NegateEdgeCost();
c=n=0;
net.Solve(n,c);
printf("%d",-c);
return 0;
}
Question 19 Load Balancing
Cost flow. Think of the warehouse as a point. The drawings are as follows:
1. Disassembly point, each warehouse point is divided into entry point and exit point, for each pair of entry point and exit point, flow INF from entry point to exit point, cost 0 side; flow INF from exit point to entry point, cost 0 side;
2. Build the total source point S, and the flow from S to each warehouse point is the number of goods in the warehouse at the cost of 0.
3. For each warehouse, flow INF is connected from the point of departure of the warehouse point to the point of entry of the previous warehouse point at the cost of 1; flow INF is connected from the point of departure of the warehouse point to the point of entry of the next warehouse point at the cost of 1;
4. Build a summary point T, from the point of departure of each warehouse point to the T-link flow is the average number of goods per warehouse, the cost of 0 side.
The minimum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
MinCost net;
int main()
{
int c,m=0,n;
scanf("%d",&n);
net.s=n<<1^1,net.t=net.v=net.s+1;
for(int i=1;i<=n;i++,m+=c)
scanf("%d",&c),
net.AddEdge(net.s,i,c,0);
m/=n;
for(int i=1;i<=n;i++)
net.AddEdge(i,i+n,INF,0),
net.AddEdge(i+n,i,INF,0),
net.AddEdge(i,(i+n-2)%n+n+1,INF,1),
net.AddEdge(i,i%n+n+1,INF,1),
net.AddEdge(i+n,net.t,m,0);
c=m=0;
net.Solve(m,c);
printf("%d",c);
return 0;
}
Question 20 Deep-sea Robot
Cost flow. Think of grid points as points and grid lines as edges. The drawings are as follows:
1. Flow 1 from each grid point to its eastern grid point at a cost of corresponding value; Flow 1 from each grid point to its northern grid point at a cost of 0;
2. Connect the flow INF from each grid point to its eastern grid point, and the flow INF from each grid point to its northern grid point, and the flow INF from each grid point to its eastern grid point, and the cost 0 side.
3. Build the total source point S, and the flow rate from S to each starting point is the number of robots and the cost is 0.
4. Construct the convergence point T. The flow rate from each destination point to T is the number of robots at the destination point, and the cost is 0.
The maximum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
MinCost net;
int main()
{
int a,b,c,p,q,x,y;
scanf("%d %d%d %d",&a,&b,&p,&q);
net.s=(p+1)*(q+1)+1,net.t=net.v=net.s+1;
for(int i=0;i<=p;i++)
for(int j=0;j<q;j++)
scanf("%d",&c),
net.AddEdge(i*(q+1)+j+1,i*(q+1)+j+2,1,-c),
net.AddEdge(i*(q+1)+j+1,i*(q+1)+j+2,INF,0);
for(int i=0;i<=q;i++)
for(int j=0;j<p;j++)
scanf("%d",&c),
net.AddEdge(i+j*(q+1)+1,i+(j+1)*(q+1)+1,1,-c),
net.AddEdge(i+j*(q+1)+1,i+(j+1)*(q+1)+1,INF,0);
while(a--)
scanf("%d %d %d",&c,&x,&y),
net.AddEdge(net.s,(q+1)*x+y+1,c,0);
while(b--)
scanf("%d %d %d",&c,&x,&y),
net.AddEdge((q+1)*x+y+1,net.t,c,0);
c=p=0;
net.Solve(p,c);
printf("%d",-c);
return 0;
}
Problem 21 The longest k-repeatable interval set problem
Cost flow. The drawings are as follows:
1. Discrete the endpoint value and construct the point with the endpoint value.
2. Build the total source point S, from S to the smallest endpoint connected flow is multiplicity, cost 0 edge;
3. For each interval, the flow rate is 1 from the left end of the interval to the right end of the interval, and the cost is the edge of the interval length.
4. Build the convergence point T, from the maximum endpoint to the T-link flow is multiplicity, cost 0 side.
The maximum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
#include<stdlib.h>
MinCost net;
int interv[1005],interval[1005],power[1005];
struct ENDPOINT
{
int interv,num;
}endpoint[2005];
int cmp(const void *p,const void *q)
{
return (*(ENDPOINT *)p).num>(*(ENDPOINT *)q).num?1:-1;
}
int main()
{
int k,n;
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++)
endpoint[i<<1].interv=endpoint[i<<1^1].interv=i+1,
scanf("%d %d",&endpoint[i<<1].num,&endpoint[i<<1^1].num),
power[i+1]=endpoint[i<<1].num<endpoint[i<<1^1].num?1:-1;
qsort(endpoint,n<<1,sizeof(ENDPOINT),cmp);
memset(interv,0,sizeof(interv));
net.s=1,net.v=2;
net.AddEdge(net.s,net.v,k,0);
interv[endpoint[0].interv]=2;
interval[endpoint[0].interv]=endpoint[0].num;
for(int i=1;i<n<<1;i++)
{
if(endpoint[i-1].num!=endpoint[i].num)
++net.v,net.AddEdge(net.v-1,net.v,INF,0);
if(interv[endpoint[i].interv]>0)
net.AddEdge(interv[endpoint[i].interv],net.v,1,(interval[endpoint[i].interv]-endpoint[i].num)*power[endpoint[i].interv]);
else
interv[endpoint[i].interv]=net.v,
interval[endpoint[i].interv]=endpoint[i].num;
}
net.t=++net.v;
net.AddEdge(net.v-1,net.t,k,0);
k=n=0;
net.Solve(k,n);
printf("%d",-n);
return 0;
}
Question 22 The longest k-repeatable segment set problem
Cost flow. With Question 21, the following drawings can also be constructed:
1. Sort the line segments in ascending order according to the left endpoint.
2. Build the total source point S, build the current limiting point S', and connect the flow from S to S', which is the side of multiplier and cost 0;
3. For each line segment, set the left endpoint as the entry point and the right endpoint as the exit point. For each pair of entry and exit points, connect flow 1 from the entry point to the exit point, and the cost is the edge of the length of the line segment.
4. Connect the flow of 1 and the cost of 0 from S'to the entry point of each line segment.
5. Build the convergence point T, from the point of departure of each line segment to the side of T with flow rate of 1 and cost of 0.
6. For each pair of line segments i and j, it is advisable to set i > J. If the abscissa of the left endpoint of line segment i is larger than that of the right endpoint of line segment j, the flow from the starting point of line segment j to the entry point of line segment i is 1, and the cost is 0.
The maximum cost flow of the graph is the answer. The original data is wrong, and the correctness of the author's code needs to be verified. The code is as follows:
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#define QueryDistance(x0,y0,x1,y1) ((int)sqrt(((x1)-(x0))*(long long)((x1)-(x0))+((y1)-(y0))*(long long)((y1)-(y0))))
MinCost net;
struct INTERVAL
{
int x0,x1,y0,y1;
}interval[1005];
int cmp(const void *p,const void *q)
{
if((*(INTERVAL *)p).x0==(*(INTERVAL *)q).x0)
return (*(INTERVAL *)p).x1>(*(INTERVAL *)q).x1?1:-1;
return (*(INTERVAL *)p).x0>(*(INTERVAL *)q).x0?1:-1;
}
int main()
{
int k,n;
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d %d %d %d\n",&interval[i].x0,&interval[i].y0,&interval[i].x1,&interval[i].y1);
qsort(interval+1,n,sizeof(INTERVAL),cmp);
net.s=n+1<<1,net.t=net.v=net.s+1;
net.AddEdge(net.s,net.s-1,k,0);
for(int i=1;i<=n;i++)
{
net.AddEdge(net.s-1,i,1,0);
net.AddEdge(i+n,net.t,1,0);
net.AddEdge(i,i+n,1,-QueryDistance(interval[i].x0,interval[i].y0,interval[i].x1,interval[i].y1));
for(int j=1;j<i;j++)
if(interval[i].x0>interval[j].x1||interval[i].x0!=interval[i].x1&&interval[j].x0!=interval[j].x1&&interval[i].x0>=interval[j].x1)
net.AddEdge(j+n,i,1,0);
}
k=n=0;
net.Solve(k,n);
printf("%d",-n);
return 0;
}
Question 23 Mars Exploration
Cost flow. Think of grid points as points and grid lines as edges. The drawings are as follows:
1. Dismantling points, each grid point is divided into entry point and exit point.
2. For each grid point, if the grid point is a stone, the flow rate of 1 and the cost of 1 are connected from the entry point of the grid point to the exit point of the grid point.
3. For each grid point, if the grid point is non-obstructive, the flow INF is connected from the entry point of the grid point to the exit point of the grid point, and the cost is 0.
4. Connect the flow INF from the outlet of each grid point to the entry point of its east grid point, and the cost 0 side; Connect the flow INF from the outlet of each grid point to the entry point of its South Grid point, and the cost 0 side.
The maximum cost flow of the graph is the answer. The code is as follows:
#include<stdio.h>
MinCost net;
int main()
{
int c,n,p,q;
scanf("%d%d%d",&n,&p,&q);
net.s=p*q<<1^1,net.t=net.v=net.s+1;
net.AddEdge(net.s,1,n,0);
net.AddEdge(p*q<<1,net.t,n,0);
for(int i=0;i<q;i++)
for(int j=0;j<p;j++)
{
scanf("%d",&c);
if(c==2)
net.AddEdge(i+j*q+1,i+j*q+p*q+1,1,-1);
if(c!=1)
net.AddEdge(i+j*q+1,i+j*q+p*q+1,INF,0);
if(i+1<q)
net.AddEdge(i+j*q+p*q+1,i+j*q+2,INF,0);
if(j+1<p)
net.AddEdge(i+j*q+p*q+1,i+(j+1)*q+1,INF,0);
}
c=n=0;
net.Solve(n,c);
printf("%d %d",n,-c);
return 0;
}
Question 24 Knight Coexistence
Minimum cut. The drawings are as follows:
1. The original picture is dyed black and white so that it is not adjacent to the lattice.
2. Construct the total source point S and connect the flow 1 side from S to each black grid point.
3. For each black grid point, the non-obstacle point from the point to the horse's step is connected to the side of the INF flow.
4. Build a summary point T, from each white grid point to the side of T connected with flow 1.
The answer is to subtract the maximum flow from the total number of non-obstacle lattices in the original map. The code is as follows:
#include<stdio.h>
MaxFlow net;
bool map[205][205];
#define Link(x,y) \
if((x)>=0&&(y)>=0&&(x)<n&&(y)<n&&map[x][y]) \
net.AddEdge(i*n+j+1,(x)*n+(y)+1,INF);
int main()
{
int m,n,x,y;
scanf("%d %d",&n,&m);
net.s=n*n+1,net.t=net.v=net.s+1;
memset(map,true,sizeof(map));
for(int i=0;i<m;i++)
scanf("%d %d",&x,&y),
map[x-1][y-1]=false;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(map[i][j])
if((i+j&1)==0)
{
net.AddEdge(net.s,i*n+j+1,1);
Link(i-2,j+1);
Link(i-1,j+2);
Link(i+1,j+2);
Link(i+2,j+1);
Link(i+2,j-1);
Link(i+1,j-2);
Link(i-1,j-2);
Link(i-2,j-1);
}
else
net.AddEdge(i*n+j+1,net.t,1);
printf("%d",n*n-m-net.Solve());
return 0;
}