题目:
题意:
有一个反动派想通过各个城市中的高速公路走最短路前往 N N N城,而我们需要在部分城市的入口或出口建立拦路点,但每个城市建立的费用是不一样的。我们需要求出最小的费用使得反动派无法走到 N N N城
分析:
因为要在最短路上跑,所以我们直接在原图上跑一遍最短路,随后再在跑出来的最短路上建立网络流。
对于唯一性的判断,我们可以根据最小割的一条性质进行处理:
若一条边为(u,v),而u与S相连,v与T相连,则这条边必定为最小割的其中之一,且方案不唯一
代码:
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define LL long long
#define LZX ILU
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
using namespace std;
struct node{
LL to,next,w;
}e[8005];
LL cnt,ls[8005],a[8005],tf[8005],n,m;
void add(LL x,LL y,LL w)
{
e[++cnt]=(node){y,ls[x],w};
ls[x]=cnt;
return;
}
struct dui{
LL num,w;
bool operator < (const dui &www) const {return w>www.w;}
};
LL ans[100005];
void dij(LL s,LL *ans)
{
for(LL i=1;i<=n;i++) ans[i]=(LL)1e18;
ans[s]=0;
priority_queue<dui> q;
q.push((dui){s,0});
while(q.size())
{
LL u=q.top().num,v=q.top().w;
q.pop();
if(v!=ans[u]) continue;
for(LL i=ls[u];i;i=e[i].next)
if(v+e[i].w<ans[e[i].to])
ans[e[i].to]=v+e[i].w,q.push((dui){e[i].to,ans[e[i].to]});
}
return;
}
LL dis[8005],dis2[8005],p[405][405];
struct wifi{
LL to,next,w;
}net[8005];
LL le[8005],tot,S,T,tt;
void addl(LL x,LL y,LL w)
{
net[++tot]=(wifi){y,le[x],w};
le[x]=tot;
net[++tot]=(wifi){x,le[y],0};
le[y]=tot;
return;
}
LL co[(LL)1e6],dt[(LL)1e6],cur[(LL)1e6];
LL dfs(LL x,LL flow)
{
if(x==T) return flow;
LL use=0;
for(LL i=cur[x];i;i=net[i].next,cur[x]=i)
{
LL v=net[i].to;
if(net[i].w&&dt[v]+1==dt[x])
{
LL tmp=dfs(v,min(flow-use,net[i].w));
net[i].w-=tmp;net[i^1].w+=tmp;use+=tmp;
if(use==flow) return use;
}
}
cur[x]=le[x];
if(!(--co[dt[x]])) dt[S]=tt;
++co[++dt[x]];
return use;
}
void dg(LL x)
{
if(tf[x]) return;
tf[x]=1;
for(LL i=le[x];i;i=net[i].next) if(net[i].w) dg(net[i].to);
return;
}
void dg2(LL x)
{
if(tf[x]) return;
tf[x]=2;
for(LL i=le[x];i;i=net[i].next) if(net[i^1].w) dg2(net[i].to);
return;
}
int main()
{
LL q=read();
while(q--)
{
cnt=0;memset(ls,0,sizeof(ls));memset(e,0,sizeof(e));
n=read(),m=read();
for(LL i=1;i<n;i++) a[i]=read();
a[n]=1e18;
for(LL i=1;i<=m;i++)
{
LL x=read(),y=read(),w=read();
add(x,y,w);add(y,x,w);
}
memset(tf,0,sizeof(tf));
dij(1,dis);dij(n,dis2);
memset(tf,0,sizeof(tf));
for(LL i=1;i<=n;i++) tf[i]=(dis[i]+dis2[i]==dis[n]);
memset(p,0,sizeof(p));
for(LL i=1;i<=n;i++)
{
if(!tf[i]) continue;
for(LL j=ls[i];j;j=e[j].next)
if(dis[i]+e[j].w==dis[e[j].to]&&tf[e[j].to]) p[i][e[j].to]++;
}
for(int i=1;i<=tt;i++) le[i]=dt[i]=co[i]=cur[i]=0;
for(int i=2;i<=cnt;i++) e[i].next=0;
tot=1;S=1;T=tt=n;
for(LL i=1;i<=n;i++)
for(LL j=1;j<=n;j++)
{
if(!p[i][j]) continue;
tt++;
addl(i,tt,(LL)p[i][j]*a[i]);addl(tt,j,(LL)p[i][j]*a[j]);
}
co[0]=tt;LL ans=0;
for(;dt[S]<tt;) ans+=dfs(S,1LL<<62);
memset(tf,0,sizeof(tf));
dg(S);
dg2(T);
LL ans2=0;
for(LL i=1;i<=tt;i++)
for(LL j=le[i];j;j=net[j].next)
if(tf[i]&&tf[net[j].to]&&tf[i]!=tf[net[j].to])
ans2+=net[j].w;
if(ans==ans2) printf("Yes "); else printf("No ");
printf("%lld\n",ans);
}
return 0;
}