最优化问题,想到网络流,思考应该是最小割还是最大流,可以先把模型转换为计算最大使用传送门的次数,先拆点,对于每个si拆成si1和si2,然后从s到si1连一条容量为要求达到访问次数的边,s2到t也连一条容量为要求达到访问次数的边,然后对于每个传送门,又si1到sj2连容量为传送门使用次数的边,跑出最大流就是最大使用传送门的次数,然后用所有的点要求达到的访问次数的总和减去maxflow就好了。
这个题我要过bzoj的数据来自测全对,在清澄OJ上也是AC,但是就是在BZOJ上WA应该是因为开O2的原因吧,反正这道题脑力AC了23333.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
queue<int>q;
struct edge{
int u,v,nxt,flow,cap;
}e[250010];
const int N=20010,INF=33000000;
int ans,n,m,te,s,t,num[N],p[N],head[N],d[N],cur[N];
void add(int u,int v,int cap)
{
e[++te].u=u;e[te].v=v;
e[te].cap=cap;e[te].nxt=head[u];
e[te].flow=0;head[u]=te;
}
int bfs()
{
memset(d,-1,sizeof(d));
d[t]=0;
q.push(t);
while (!q.empty())
{
int v=q.front();
for (int i=head[v];i!=-1;i=e[i].nxt)
{
int u=e[i].v;
if (d[u]==-1&&e[i].cap==0)
{
d[u]=d[v]+1;
q.push(u);
}
}
q.pop();
}
}
int augment()
{
int x=t,a=INF;
while (x!=s)
{
a=min(a,e[p[x]].cap-e[p[x]].flow);
x=e[p[x]].u;
}
x=t;
while (x!=s)
{
e[p[x]].flow+=a;
e[p[x]^1].flow-=a;
x=e[p[x]].u;
}
return a;
}
int isap()
{
int flow=0;
bfs();
memset(num,0,sizeof(num));
for (int i=1;i<=n;i++)
if (d[i]!=-1)num[d[i]]++;
else d[0]++;
int x=s;
while (d[s]<n)
{
if (x==t)
{
flow+=augment();
x=s;
}
int ok=0;
for (int i=cur[x];i!=-1;i=e[i].nxt)
{
int v=e[i].v;
if (d[v]+1==d[x]&&e[i].cap>e[i].flow)
{
ok=1;
p[v]=i;
cur[x]=i;
x=v;
break;
}
}
if (!ok)
{
if (--num[d[x]]==0)break;
int m=n-1;
for (int i=head[x];i!=-1;i=e[i].nxt)
{
int v=e[i].v;
if (e[i].cap>e[i].flow)m=min(m,d[v]);
}
d[x]=m+1;
num[d[x]]++;
cur[x]=head[x];
if (x!=s)x=e[p[x]].u;
}
}
return flow;
}
int main()
{
freopen("std.in","r",stdin);
memset(head,-1,sizeof(head));
memset(cur,-1,sizeof(cur));
int u,v,cap;te=-1;
scanf("%d%d",&n,&m);
int k=n<<1;
s=k+1,t=k+2;
for (int i=1;i<=n;i++)
{
scanf("%d",&cap);
add(s,i,cap),add(i,s,0);
add(i+n,t,cap),add(t,i+n,0);
ans+=cap;
}
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&cap);
add(u,v+n,cap);
add(v+n,u,0);
}
n=k+2;
for (int i=1;i<=n;i++)
cur[i]=head[i];
cout<<ans-isap()<<endl;
return 0;
}