zoukankan      html  css  js  c++  java
  • P3973 [TJOI2015]线性代数 最小割

    题意:

    戳这里

    分析:

    [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})

    具体做法就是:

    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
    ",ans);
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
    
  • 相关阅读:
    Linux ALSA音频库(一) 交叉编译 详细说明
    在KEIL下查看单片机编程内存使用情况
    Linux Socket
    QT报错随手记
    Cortex-M3双堆栈MSP和PSP+函数栈帧
    Linux命令
    cdev_alloc与cdev_init区别
    一些编译报错
    SFUD+FAL+EasyFlash典型场景需求分析,并记一次实操记录
    RTThread DFS文件系统使用: 基于使用SFUD驱动的SPI FLASH之上的ELM FATFS文件系统
  • 原文地址:https://www.cnblogs.com/youth518/p/14387577.html
Copyright © 2011-2022 走看看