题解 P6061 【[加油武汉]疫情调查】
update1:感谢 @linfourxu 指出文章错误,已经更正。
update2:上次修改不完全,仍有残余错误。
给一个有向图,求用若干个环(或点)将整张图覆盖的最小花费。
求最小覆盖,想到带权二分图匹配问题,可以用费用流一波带走。
我们发现
-
从
s 向u 连一条流量为1 ,费用为0 的边; -
从
u' 向t 连一条流量为1 ,费用为0 的边; -
对于每一个点
u ,从u 向u' 连一条流量为\inf ,费用为a_u 的边; -
对于点对
(u,v) ,如果从u 可以到达v ,就从u 向v' 连一条流量为1 ,费用为dis_{i\rightarrow j} 的边。
我们发现这张图一定存在完美匹配,那么就跑一遍最小费用最大流就可以拿到 70pts。
为什么会超时呢?因为跑一遍 Floyd 会使
我们考虑减少边的数量,由于最短路是由若干条路径拼成的,我们可以只在网络流建模中连接数据给出的边,同时从
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define int unsigned long long
struct edge
{
int nxt,to,weight,value;
}e[1000001<<1];
int n,m,tot=1,h[10005],dep[10005],cur[10005],s,t,a[5001],cost,ans,hg[10005];
bool vis[10005];
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void add(int x,int y,int w,int val)
{
e[++tot].nxt=h[x];
h[x]=tot;
e[tot].to=y;
e[tot].weight=w;
e[tot].value=val;
}
inline bool Dijkstra()
{
for(register int i=0;i<=t;++i)
{
vis[i]=0;
dep[i]=0x3f3f3f3f;
cur[i]=h[i];
}
__gnu_pbds::priority_queue<pair<int,int>,greater<pair<int,int> >,pairing_heap_tag> q;
q.push(make_pair(0,t));
dep[t]=0;
while(!q.empty())
{
pair<int,int> k=q.top();
q.pop();
if(vis[k.second])
continue;
vis[k.second]=1;
for(register int i=h[k.second];i;i=e[i].nxt)
if(e[i^1].weight&&dep[e[i].to]>dep[k.second]-e[i].value+hg[k.second]-hg[e[i].to])
{
dep[e[i].to]=dep[k.second]-e[i].value+hg[k.second]-hg[e[i].to];
q.push(make_pair(dep[e[i].to],e[i].to));
}
}
return dep[0]!=dep[s];
}
int dfs(int k,int f)
{
int r=0;
if(!f||k==t)
{
vis[t]=1;
ans+=f;
return f;
}
int used=0;
vis[k]=1;
for(register int i=cur[k];i;i=e[i].nxt)
{
cur[k]=i;
if((!vis[e[i].to]||e[i].to==t)&&dep[e[i].to]==dep[k]-e[i].value+hg[k]-hg[e[i].to]&&e[i].weight)
if((r=dfs(e[i].to,min(f-used,e[i].weight))))
{
cost+=e[i].value*r;
e[i].weight-=r;
e[i^1].weight+=r;
used+=r;
if(f==used)
{
//vis[k]=0;
break;
}
}
}
return used;
}
inline int dinic()
{
while(Dijkstra())
{
vis[t]=1;
while(vis[t])
{
memset(vis,0,sizeof(vis));
dfs(s,1<<20);
}
memset(vis,0,sizeof(vis));
for(register int i=0;i<=t;++i)
hg[i]+=dep[i];
}
return cost;
}
signed main()
{
n=read(),m=read();
s=n<<1|1;
t=s+1;
for(register int i=1;i<=n;++i)
{
a[i]=read();
add(s,i,1,0);
add(i,s,0,0);
add(i+n,t,1,0);
add(t,i+n,0,0);
add(i,i+n,1<<20,a[i]);
add(i+n,i,0,-a[i]);
add(i+n,i,1<<20,0);
add(i,i+n,0,0);
}
for(register int i=1;i<=m;++i)
{
int x=read(),y=read(),w=read();
add(x,y+n,1<<20,w);
add(y+n,x,0,-w);
}
printf("%lld\n",dinic());
return 0;
}