版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意:
T组数据,n个点和m条边组成一个有向图,边是单向边,每条边都有权值,需要你删去一些边使得1到n的最短路严格变长,删掉边的费用为边的长度,求最小花费。
思路:先跑一遍最短路求出1到其他点的最短距离,然后 倒着dfs 求出最短路的DAG的所有边,重新建图,跑最小割就行了。//套板子
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pa pair<ll,ll>
using namespace std;
const ll maxn=1e4+5;
const ll maxm=1e7+10;
const ll mod=1e9+7;
vector< pair <int,int> >ve[maxn];
ll dis[maxn];
int n,m,cnt=-1,head[maxn],dep[maxn];
bool vis[maxn];
struct node {
int to,next,v;
} edge[maxn*2]; //maxn=1e4
void add_edge(int a,int b,int c) { //边数从0开始,每次加上反向边,这样奇偶交替加边,重边无所谓,存图
edge[++cnt].to=b;
edge[cnt].next=head[a];
edge[cnt].v=c;
head[a]=cnt;
}
bool bfs() { //分层图
for(int i=1; i<=n; i++)dep[i]=1e9;
dep[1]=0;
queue<int>que;
que.push(1);
while(que.size()) {
int now=que.front();
que.pop();
for(int i=head[now]; i!=-1; i=edge[i].next) {
int to=edge[i].to;
int v=edge[i].v;
if(v&&dep[to]>dep[now]+1) {
dep[to]=dep[now]+1;
que.push(to);
}
}
}
if(dep[n]==1e9)return false;
else return true;
}
int dfs(int x,int lowflow) { //找最短增广路
if(x==n||lowflow==0)return lowflow;
int reslow=0;
int used=0;
for(int i=head[x]; i!=-1; i=edge[i].next) {
int to=edge[i].to;
if(edge[i].v&&dep[x]+1==dep[to]) {
if(reslow=dfs(to,min(lowflow,edge[i].v))) {
edge[i].v-=reslow;
edge[i^1].v+=reslow;
used+=reslow;
lowflow-=reslow;
if(lowflow<=0)break;
}
}
}
return used;
}
void Dinic() {
ll maxflow=0;
int lowflow;
while(bfs()) { //找增广路的分层图
while(lowflow=dfs(1,1e9)) { //若return 0则说明找不到最短增广路,则重新跑一下bfs,找增长的增广路。
maxflow+=lowflow; //最大流=各增广路的流相加
}
}
printf("%lld\n",maxflow);
}
void dijkstra() { //优先队列实现dijkstra
for(int i=1; i<=n; i++)dis[i]=1e18,vis[i]=false;
dis[1]=0;
priority_queue<pair<ll,int> >que;
que.push(make_pair(0,1));
while(que.size()) {
pair<ll,int>now=que.top();
que.pop();
if(vis[now.second])continue;
vis[now.second]=true;
for(int i=0; i<ve[now.second].size(); i++) {
int to=ve[now.second][i].first;
int w=ve[now.second][i].second;
if(dis[to]>dis[now.second]+w) {
dis[to]=dis[now.second]+w;
que.push(make_pair(-dis[to],to));
}
}
}
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
scanf("%d %d",&n,&m);
for(int i=1; i<=m; i++) {
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
ve[a].push_back(make_pair(b,c));
}
dijkstra();
if(dis[n]==1e18) { //判断最先是否可以到达n点
printf("0\n");
continue;
}
//for(int i=0; i<=n; ++i) cout << dis[i] << " ";
//return 0;
for(int i=1; i<=n; i++)head[i]=-1;
cnt=-1;
for(int i=1; i<=n; i++) {
for(int j=0; j<ve[i].size(); j++) {
int a=i,b=ve[i][j].first,c=ve[i][j].second;
if(dis[a]+c==dis[b])add_edge(a,b,c),add_edge(b,a,0); //存入有向图和反向残存图
}
}
Dinic();
for(int i=1; i<=n; i++)ve[i].clear();
}
return 0;
}