训练的题目
最大流
题意:题意直白,就是一个网格从(0,0)编号到(N-1,M-1),每个点可以走到和它相连的4个点,没条边都有容量,为你从(0,0)到(N-1,M-1)的最大流
1.建图细心一点不要出错,注意检查
2.无向图,本来建的是无向图,无端端注释掉一部分,WA了一次才想起来怎么注释掉了,改回来过了
3.建图后,直接上最大流模板,这里用EK
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; #define N 10100 #define M 100100 #define INF 0x3f3f3f3f int n,row,col,tot; int head[N]; struct edge { int u,v,cap,flow,next; }e[M]; int a[N]; //用于bfs搜索时记录最小残余容量 int p[N]; //邻接表记录路径 queue<int>q; //用于bfs搜索 void add(int u ,int v , int cap ,int flow) { e[tot].u = u; e[tot].v = v; e[tot].cap = cap; e[tot].flow = flow; e[tot].next = head[u]; head[u] = tot++; } void EK(int s ,int t) { int FLOW = 0; while(1) { while(!q.empty()) q.pop(); memset(a,0,sizeof(a)); memset(p,-1,sizeof(p)); a[s] = INF; q.push(s); while(!q.empty()) //bfs { int u = q.front(); q.pop(); for(int k=head[u]; k!=-1; k=e[k].next) { int v = e[k].v; int cap = e[k].cap; int flow = e[k].flow; if(!a[v] && cap > flow) //未搜索过,且可以增流 { p[v] = k; //记录哪条边 if(a[u] < cap-flow) a[v] = a[u]; else a[v] = cap - flow; q.push(v); } } } if(!a[t]) break; //找不到增广路 for(int k=p[t]; k!=-1; k=p[e[k].u]) //沿路径返回增广 { e[k].flow += a[t]; e[k^1].flow -= a[t]; } FLOW += a[t]; } printf("%d\n",FLOW); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&row,&col); memset(head,-1,sizeof(head)); tot = 0; n = row * col - 1; int cap,u,v; //先输入横边 for(int i=0; i<row; i++) for(int j=0; j<col-1; j++) { scanf("%d",&cap); u=i*col+j; //当前点 v=i*col+j+1; //其右边点 add(u,v,cap,0); //建立正边u--->v add(v,u,0,0); //反边,容量为0 add(v,u,cap,0); //无向图,正边v--->u add(u,v,0,0); //反边,容量为0 } //输入竖边 for(int i=0; i<row-1; i++) for(int j=0; j<col; j++) { scanf("%d",&cap); u=i*col+j; //当前点 v=(i+1)*col+j; //其下面的点 add(u,v,cap,0); //正边u--->v add(v,u,0,0); //反边,容量为0 add(v,u,cap,0); //正边v--->u add(u,v,0,0); //反边,容量为0 } EK(0,n); } return 0; }