题意:
分析:
[D=sum_{j=1}^nA_{1,j} imes (sum_{i=1}^nA_{1,i}B_{i,j}-C_{1,j})
]
我们观察式子可以发现 (B_{i,j}) 会被选当且仅当 (A_{1,i},A_{1,j}) 都为 1,(-C_{1,j}) 会被选当且仅当 (A_{1,j}) 为 1
也就是说 (B_{i,j}) 和 (-C_{1,i},-C_{1,j}) 必须同时存在,也就是说选了 (B_{i,j}) 就得减少 (C_{1,i}+C_{1,j}) 这个东西好像很最小割,我们只要把 (B_{i,j}) 到汇点路径上的流量表示为 (C_{1,i}+C_{1,j}) 那么要么不选 (B_{i,j}) 要么必须减少 (C_{1,i}+C_{1,j})
具体做法就是:
- 对于每一个 (B_{i,j},C_{1,i}) 建立一个点
- 源点向所有的 (B_{i,j}) 连一条流量为 (B_{i,j}) 的边,(C_{1,i}) 向汇点连一条流量为 (C_{1,i}) 的边
- 每一个 (B_{i,j}) 向 (C_{1,i},C_{1,j}) 连一条流量为 (inf) 的边
- 求最小割,答案等于 (sum B_{i,j}-mincut)
代码:
#include<bits/stdc++.h>
#define inl inline
#define reg register
#define id(i,j) (i-1)*n+j
using namespace std;
namespace zzc
{
typedef long long ll;
inl ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const ll maxn = 3e5+5;
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll n,cnt=1,st,ed,ans;
ll head[maxn],dep[maxn],cur[maxn];
queue<ll> q;
struct edge
{
ll to,nxt,w;
}e[maxn<<3];
inl void add(ll u,ll v,ll w)
{
e[++cnt].to=v;
e[cnt].w=w;
e[cnt].nxt=head[u];
head[u]=cnt;
}
inl void add_edge(ll u,ll v,ll w)
{
add(u,v,w);add(v,u,0);
}
inl bool bfs()
{
for(reg ll i=st;i<=ed;i++) dep[i]=-1;
dep[st]=0;q.push(st);
while(!q.empty())
{
ll u=q.front();q.pop();
for(reg ll i=head[u];i;i=e[i].nxt)
{
ll v=e[i].to;
if(e[i].w&&dep[v]==-1)
{
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[ed]!=-1;
}
ll dfs(ll u,ll flow)
{
if(u==ed) return flow;
ll w,used=0;
for(reg ll &i=cur[u];i;i=e[i].nxt)
{
ll v=e[i].to;
if(e[i].w&&dep[v]==dep[u]+1)
{
w=dfs(v,min(flow-used,e[i].w));
e[i].w-=w;
e[i^1].w+=w;
used+=w;
if(used==flow) return used;
}
}
if(!used) dep[u]=-1;
return used;
}
inl void dinic()
{
while(bfs())
{
memcpy(cur,head,sizeof(head));
ans-=dfs(st,inf);
}
}
void work()
{
ll a;
n=read();st=0;ed=n*n+n+1;
for(reg ll i=1;i<=n;i++) for(reg ll j=1;j<=n;j++) a=read(),ans+=a,add_edge(st,id(i,j),a),add_edge(id(i,j),id(n+1,i),inf),add_edge(id(i,j),id(n+1,j),inf);
for(reg ll i=1;i<=n;i++) a=read(),add_edge(id(n+1,i),ed,a);
dinic();
printf("%lld
",ans);
}
}
int main()
{
zzc::work();
return 0;
}