Path
思路:这道题需要用到最短路和最小割。首先需要用最短路,找到最短的路径,然后再利用
dis[e[j].s]+e[j].w==dis[e[j].t
这个条件,重新建图,在重新建的图当中,保证了所有的路径长度都是最短路,那么便可以进行最小割的操作,最小割即最大流,所以,可以对新建的图写dinic
求最大流
代码:
// Created by CAD on 2019/9/14.
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f
#define mst(name, value) memset(name,value,sizeof(name))
#define ll long long
using namespace std;
const int maxn=3e5+10;
struct node {
ll s, t, w, next;
} e[maxn << 1], e2[maxn << 1];
ll head[maxn], head2[maxn], cnt, cnt2;
void init()
{
mst(head, -1), mst(head2, -1), cnt=cnt2=0;
}
void add(ll s, ll t, ll w)
{
e[cnt].s=s, e[cnt].t=t, e[cnt].w=w, e[cnt].next=head[s];
head[s]=cnt++;
}
void add2(ll s, ll t, ll w)
{
e2[cnt2].s=s, e2[cnt2].t=t, e2[cnt2].w=w, e2[cnt2].next=head2[s];
head2[s]=cnt2++;
}
struct p {
ll dis, num;
bool operator<(const p &a) const
{
return a.dis<dis;
}
};
ll dis[maxn], vis[maxn],d[maxn];;
void dij(ll n)
{
priority_queue<p> q;
for (ll i=1; i<=n; ++i)
dis[i]=INF, vis[i]=0;
q.push({0, 1});
dis[1]=0;
while (!q.empty())
{
ll x=q.top().num;
q.pop();
if (vis[x])
continue;
vis[x]=1;
for (ll i=head[x]; ~i; i=e[i].next)
{
ll y=e[i].t;
if (dis[y]>dis[x]+e[i].w)
{
dis[y]=dis[x]+e[i].w;
q.push({dis[y], y});
}
}
}
}
bool bfs(ll s, ll t)
{
queue<ll> q;
mst(d, 0);
d[s]=1;
q.push(s);
while (!q.empty())
{
ll x=q.front();
q.pop();
for (ll i=head2[x]; ~i; i=e2[i].next)
{
ll y=e2[i].t;
if (e2[i].w && !d[y])
d[y]=d[x]+1, q.push(y);
}
}
return d[t];
}
ll dfs(ll x, ll t, ll lim)
{
if (x==t) return lim;
ll add, ans=0;
for (ll i=head2[x]; ~i; i=e2[i].next)
{
ll y=e2[i].t;
if (d[y]==d[x]+1 && e2[i].w)
{
add=dfs(y, t, min(lim, e2[i].w));
e2[i].w-=add;
e2[i^1].w+=add;
ans+=add;
lim-=add;
if (!lim) break;
}
}
if (!ans) d[x]=-1;
return ans;
}
ll dinic(ll s, ll t)
{
ll ans=0;
while (bfs(s, t))
ans+=dfs(s, t, INF);
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--)
{
ll n, m;
init();
cin >> n >> m;
ll x, y, z;
for (ll i=1; i<=m; ++i)
cin >> x >> y >> z, add(x, y, z);
dij(n);
for (ll i=1; i<=n; ++i)
for (ll j=head[i]; ~j; j=e[j].next)
if (dis[e[j].s]+e[j].w==dis[e[j].t])
add2(e[j].s, e[j].t, e[j].w), add2(e[j].t, e[j].s, 0);
cout << dinic(1, n) << endl;
}
return 0;
}