现在假设受众已有 求图的所有最短路径 的前置知识
推荐阅读:白书P209 看懂最大流&最小割
今天没时间重构代码了。。。
就随便注释一下
题目呢是签到题
意思是给一个有向图
一个人要从1点走到n点
我们要阻碍他走最短路
而你堵塞一条边的代价就是这条边的长度
问最小代价
要是看懂了最小割
就知道这题几乎就是板子题
先用优先队列优化最短路,求所有最短路径的所有边
题解的方法可以学一手
采用的方法是先更新好所有点的最短距离 (题中的sp数组)
然后遍历所有边
接着如果说两个点的最短距离之差刚好是边的长度
那么这条边就是在最短路上
就是题解那个蜜汁公式的意思
for(int pos=1;pos<=n;++pos)
for(auto &e : D::G[pos])
if(sp[e.to]-sp[pos]==e.v)
I::AddEdge(pos,e.to,e.v); 上图的下面的for等价于
for(int i=0;i<D::G[pos].size();i++){
D::Edge e=D::G[pos][i];
} 学一手auto自适应类型
然后用最大流求答案。。。。
似乎就没了
#include
template
bool Reduce(T &a,T const &b) {
return a>b?a=b,1:0;
}
const int XN=1e4+11;
const int INF=2e9;
const long long oo=1e18;
int n;
long long sp[XN];
namespace D {
struct Edge {
int to,v;
};
std::vector G[XN];
//优先队列优化
void Run() {
static bool ud[XN];
std::priority_queue,std::vector >,std::greater > > Q;//小根堆
std::fill(sp+1,sp+1+n,oo);
std::fill(ud+1,ud+1+n,0);
sp[1]=0;
Q.push(std::make_pair(0,1));
while(!Q.empty()) {
int pos=Q.top().second;Q.pop();
if(ud[pos])
continue;
ud[pos]=1;
for(auto int & e : G[pos]) {
int u=e.to;
if(Reduce(sp[u],sp[pos]+e.v))
Q.push(std::make_pair(sp[u],u));
}
}
}
}
namespace I {
//最大流求解
struct Edge {
int to,cap,v;
Edge *rev,*pre;
}*G[XN],*preArc[XN];
void AddEdge(int x,int y,int c) {
G[x]=new Edge{y,c,0,NULL,G[x]};
G[y]=new Edge{x,0,0,G[x],G[y]};
G[x]->rev=G[y];
}
int Aug() {
int d=INF;
for(int pos=n;preArc[pos];pos=preArc[pos]->rev->to)
Reduce(d,preArc[pos]->cap-preArc[pos]->v);
for(int pos=n;preArc[pos];pos=preArc[pos]->rev->to) {
preArc[pos]->v+=d;
preArc[pos]->rev->v-=d;
}
return d;
}
long long Run() {
static int num[XN],d[XN];
static Edge *cArc[XN];
std::fill(num+1,num+n,0);
std::fill(d+1,d+1+n,0);
std::copy(G+1,G+1+n,cArc+1);
num[0]=n;preArc[1]=0;
long long flow=0;
for(int pos=1;d[1]<n;) {
if(pos==n) {
flow+=Aug();
pos=1;
}
bool adv=0;
for(Edge *&e=cArc[pos];e;e=e->pre) {
int u=e->to;
if(e->cap>e->v && d[u]+1==d[pos]) {
adv=1;
preArc[pos=u]=e;
break;
}
}
if(!adv) {
if(--num[d[pos]]==0)
break;
d[pos]=n;
for(Edge *e=cArc[pos]=G[pos];e;e=e->pre)
if(e->cap>e->v)
Reduce(d[pos],d[e->to]+1);
num[d[pos]]++;
if(pos!=1)
pos=preArc[pos]->rev->to;//cArc
}
}
return flow;
}
}
int main() {
//freopen("test1.in","r",stdin);
std::ios::sync_with_stdio(0);
std::cin.tie(0);
int T;std::cin>>T;
while(T--) {
int m;std::cin>>n>>m;
for(int i=1;i<=n;++i) {
D::G[i].clear();
I::G[i]=0;
}
for(int i=1;i<=m;++i) {
int x,y,v;
std::cin>>x>>y>>v;
D::G[x].push_back({y,v});
}
D::Run();
if(sp[n]==oo)
std::cout<<0<<'\n';
else {
//蜜汁公式 求出所有最短路径边
for(int pos=1;pos<=n;++pos)
for(auto &e : D::G[pos])
if(sp[e.to]-sp[pos]==e.v)
I::AddEdge(pos,e.to,e.v);
std::cout<<I::Run()<<'\n';
}
}
return 0;
} 


京公网安备 11010502036488号