​传送门​​​ 思路:将图中的最短路挑出来,加到网络中,跑一遍最大流。
dis[v]-dis[u]==1判断是否在最短路中。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<climits>
#include<algorithm>
#include<complex>
#include<iostream>
#include<map>
#include<queue>
#include<vector>
#define mem(a,b) memset(a,b,sizeof a)
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define ll long long
#define maxn 10005
using namespace std;
int n, m; //点数、边数
int s, t; //原点、汇点
struct node {
int v, next;
ll cap;
} mp[maxn * 10];
struct Node {
int u, v, w, next;
} e[maxn];
int pre[maxn], dis[maxn], cur[maxn]; //cur为当前弧优化,dis存储分层图中每个点的层数(即到原点的最短距离),pre建邻接表
int cnt, edge_num;
int vis[maxn],Dis[maxn];
int head1[maxn], head[maxn];
void init() { //不要忘记初始化
cnt = 1;
edge_num = 1;
mem(pre, -1);
mem(head1, -1);
}
void add(int u, int v, int w) { //加边
mp[++edge_num].v = v;
mp[edge_num].cap = w;
mp[edge_num].next = pre[u];
pre[u] = edge_num;
}
void add_sfa(int u, int v, int w) {
e[++cnt].u = u;
e[cnt].v = v;
e[cnt].w = w;
e[cnt].next = head1[u];
head1[u] = cnt;
}
bool bfs(int s) { //建分层图
memset(dis, -1, sizeof(dis));
queue<int>q;
while(!q.empty())
q.pop();
q.push(s);
dis[s] = 0;
int u, v;
while(!q.empty()) {
u = q.front();
q.pop();
for(int i = pre[u]; i != -1; i = mp[i].next) {
v = mp[i].v;
if(dis[v] == -1 && mp[i].cap > 0) {
dis[v] = dis[u] + 1;
q.push(v);
if(v == t)
break;
}
}
}
return dis[t] != -1;
}
ll dfs(int u, ll cap) { //寻找增广路
if(u == t || cap == 0)
return cap;
ll res = 0, f;
for(int &i = cur[u]; i != -1; i = mp[i].next) {
int v = mp[i].v;
if(dis[v] == dis[u] + 1 && (f = dfs(v, min(cap - res, mp[i].cap))) > 0) {
mp[i].cap -= f;
mp[i ^ 1].cap += f;
res += f;
if(res == cap)
return cap;
}
}
if(!res)
dis[u] = -1;
return res;
}
ll dinic() {
ll ans = 0;
while(bfs(s)) {
for(int i = 1; i <= n; i++)
cur[i] = pre[i];
ans += dfs(s, inf);
}
return ans;
}
void spfa(int u) {
mem(vis, 0);
vis[u] = 1; ///判段结点是否在队列中
mem(Dis, 0x3f); ///只会截取第一个字节
Dis[u] = 0;
queue<int>q;
q.push(u);
while(!q.empty()) {
u = q.front();
q.pop();///1.23
vis[u] = 0;
for(int j = head1[u]; ~j; j = e[j].next) {///j=-1;
int v = e[j].v;
if(Dis[v] > Dis[u] + 1) {
Dis[v] = Dis[u] + 1;///松弛操作
if(!vis[v]) {
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main() {
int T;
cin >> T;
while(T--) {
init();
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int u,w,v;
cin >> u >> v >> w;
add_sfa(u, v, w);
add_sfa(v, u, w);
}
spfa(1);
for(int i = 1; i <= n; i++)
for(int j = head1[i]; ~j; j = e[j].next) {
int v = e[j].v;
if(Dis[v] - Dis[i] == 1)
add(i, v, e[j].w), add(v, i, 0);
}
s=1,t=n;
cout<<dinic()<<endl;
}
return 0;
}

弧优化模板

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<climits>
#include<algorithm>
#include<complex>
#include<iostream>
#include<map>
#include<queue>
#include<vector>
#define mem(a,b) memset(a,b,sizeof a)
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define ll long long
#define maxn 10005
using namespace std;
int n, m; //点数、边数
int s, t; //原点、汇点
struct node {
int v, next;
ll cap;
} mp[maxn * 10];
struct Node {
int u, v, w, next;
} e[maxn];
int pre[maxn], dis[maxn], cur[maxn]; //cur为当前弧优化,dis存储分层图中每个点的层数(即到原点的最短距离),pre建邻接表
int cnt, edge_num;
int vis[maxn],Dis[maxn];
int head1[maxn], head[maxn];
void init() { //不要忘记初始化
edge_num = 1;
mem(pre, -1);
}
void add(int u, int v, int w) { //加边
mp[++edge_num].v = v;
mp[edge_num].cap = w;
mp[edge_num].next = pre[u];
pre[u] = edge_num;
}
bool bfs(int s) { //建分层图
memset(dis, -1, sizeof(dis));
queue<int>q;
while(!q.empty())
q.pop();
q.push(s);
dis[s] = 0;
int u, v;
while(!q.empty()) {
u = q.front();
q.pop();
for(int i = pre[u]; i != -1; i = mp[i].next) {
v = mp[i].v;
if(dis[v] == -1 && mp[i].cap > 0) {
dis[v] = dis[u] + 1;
q.push(v);
if(v == t)
break;
}
}
}
return dis[t] != -1;
}
ll dfs(int u, ll cap) { //寻找增广路
if(u == t || cap == 0)
return cap;
ll res = 0, f;
for(int &i = cur[u]; i != -1; i = mp[i].next) {
int v = mp[i].v;
if(dis[v] == dis[u] + 1 && (f = dfs(v, min(cap - res, mp[i].cap))) > 0) {
mp[i].cap -= f;
mp[i ^ 1].cap += f;
res += f;
if(res == cap)
return cap;
}
}
if(!res)
dis[u] = -1;
return res;
}
ll dinic() {
ll ans = 0;
while(bfs(s)) {
for(int i = 1; i <= n; i++)
cur[i] = pre[i];
ans += dfs(s, inf);
}
return ans;
}
int main() {
int T;
cin >> T;
while(T--) {
init();
cin >> n >> m;
}
return 0;
}