码迷,mamicode.com
首页 > 其他好文 > 详细

P3973 [TJOI2015]线性代数 最小割

时间:2021-02-09 11:54:55      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:etc   n+1   最小割   com   最小   str   就是   pre   tchar   

题意:

戳这里

分析:

\[D=\sum_{j=1}^nA_{1,j}\times (\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}\)

具体做法就是:

  1. 对于每一个 \(B_{i,j},C_{1,i}\) 建立一个点
  2. 源点向所有的 \(B_{i,j}\) 连一条流量为 \(B_{i,j}\) 的边,\(C_{1,i}\) 向汇点连一条流量为 \(C_{1,i}\) 的边
  3. 每一个 \(B_{i,j}\)\(C_{1,i},C_{1,j}\) 连一条流量为 \(\inf\) 的边
  4. 求最小割,答案等于 \(\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\n",ans);
    }

}

int main()
{
    zzc::work();
    return 0;
}

P3973 [TJOI2015]线性代数 最小割

标签:etc   n+1   最小割   com   最小   str   就是   pre   tchar   

原文地址:https://www.cnblogs.com/youth518/p/14387577.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!