zoukankan      html  css  js  c++  java
  • bzoj千题计划300:bzoj4823: [Cqoi2017]老C的方块

    http://www.lydsy.com/JudgeOnline/problem.php?id=4823

    讨厌的形状就是四联通图

    左右各连一个方块

    那么破坏所有满足条件的四联通就好了

    按上图方式染色之后,任意满足要求的四联通块一定可以是

    黑色-->紫左-->紫右-->白色

    只要破坏三个箭头中的一个即可

    所以可以构建最小割模型

    1、源点向黑色格连流量为格子代价的边

    2、黑色格向相邻的紫色格连inf边

    3、与黑色格相邻的紫色格向与白色格相邻的紫色格连 流量 为 两个紫色格较小代价 的边

    4、与白色相邻的紫色格向白色格连inf边

    5、白色格向汇点连流量为格子代价的边

    染完之后长这样:

     

    注意:

    不要在枚举紫色格子的过程中连源点汇点的边

    这样会导致连重边

    比如这样黑色格子就会与源点有重边,两个紫色格子各贡献了一条边

    但实际我们只能用一条边

    所以可以标记哪些格子与源点、汇点有边,最后再连

    (再次吐槽一次bzoj的题面~~)

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<map>
    #include<queue>
    
    using namespace std;
    
    typedef long long LL;
    
    #define N 100002
    #define M 1400001
    
    const int inf=2e9;
    
    map<LL,int>mp;
    
    int n,m,k;
    int xi[N],yi[N],zi[N];
    
    int front[N],nxt[M<<1],to[M<<1],cap[M<<1],tot=1;
    int lev[N],cur[N];
    int src,decc;
    queue<int>q;
    
    bool uses[N],uset[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    LL turn(int i,int j)
    {
        return 1LL*(i-1)*m+j;
    }
    
    void init()
    {
        read(m); read(n); read(k);
        int y,x;
        for(int i=1;i<=k;++i)
        {
            read(yi[i]); read(xi[i]); read(zi[i]);
            mp[turn(xi[i],yi[i])]=i;
        }
        decc=k+1;
    }
    
    void add(int u,int v,int val)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; cap[tot]=val;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; cap[tot]=0;
    //    printf("%d %d %d
    ",u,v,val);
    }
    
    void Add(int x,int l,int r,int y)
    {
        if(y%4==1 || !(y%4))
        {
            uses[x]=true;
            add(x,l,inf);
        }
        else
        {
            uset[x]=true;
            add(r,x,inf);
        }
    }
    
    void build()
    {
        int x,y;
        int tmp,l,r;
        int l1,l2,l3,r1,r2,r3;
        for(int i=1;i<=k;++i)
        {
            x=xi[i]; y=yi[i];
            if(y==m) continue;
            if(((x&1) && y%4==1) || (!(x&1) && y%4==3)) 
            {
                tmp=mp[turn(x,y+1)];
                if(!tmp) continue;
            }
            else continue;
            if(x>1) l1=mp[turn(x-1,y)]; else l1=0;
            if(x<n) l2=mp[turn(x+1,y)];    else l2=0;
            if(y>1) l3=mp[turn(x,y-1)]; else l3=0;
            if(!(l1||l2||l3)) continue; 
            if(x>1) r1=mp[turn(x-1,y+1)]; else r1=0;
            if(x<n) r2=mp[turn(x+1,y+1)]; else r2=0;
            if(y<n-1) r3=mp[turn(x,y+2)]; else r3=0;
            if(!(r1||r2||r3)) continue; 
            l=i; r=tmp;
            if(y%4==3) swap(l,r);
            add(l,r,min(zi[l],zi[r]));
            if(l1) Add(l1,l,r,yi[l1]);
            if(l2) Add(l2,l,r,yi[l2]);
            if(l3) Add(l3,l,r,yi[l3]);
            if(r1) Add(r1,l,r,yi[r1]);
            if(r2) Add(r2,l,r,yi[r2]);
            if(r3) Add(r3,l,r,yi[r3]);
        }
        for(int i=1;i<=k;++i) 
            if(uses[i]) add(src,i,zi[i]);
        for(int i=1;i<=k;++i)
            if(uset[i]) add(i,decc,zi[i]);
    }
    
    bool bfs()
    {
        while(!q.empty()) q.pop();
        for(int i=src;i<=decc;++i) lev[i]=-1,cur[i]=front[i];
        lev[src]=0;
        q.push(src);
        int now,t;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            for(int i=front[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==-1 && cap[i])
                {
                    lev[t]=lev[now]+1;
                    if(t==decc) return true;
                    q.push(t);
                }
            }
        }
        return false;
    }
    
    int dinic(int now,int flow)
    {
        if(now==decc) return flow;
        int rest=0,delta,t;
        for(int &i=cur[now];i;i=nxt[i])
        {
            t=to[i];
            if(lev[t]>lev[now] && cap[i])
            {
                delta=dinic(t,min(flow-rest,cap[i]));
                if(delta)
                {
                    cap[i]-=delta;
                    cap[i^1]+=delta;
                    rest+=delta;
                    if(rest==flow) break;
                }
            }
        }
        if(rest!=flow) lev[now]=-1;
        return rest;
    }
    
    void solve()
    {
        int ans=0;
        while(bfs()) ans+=dinic(src,inf);
        printf("%d",ans);
    }
    
    int main()
    {
        freopen("data.in","r",stdin);
        freopen("my.out","w",stdout);
        init();
        build();
        solve();
    }
  • 相关阅读:
    安装libgl1-mesa-dri:i386重启后黑屏问题解决
    adb连接安卓模拟器
    编译andorid内核
    android镜像文件说明
    ubantu14.04配置android编译环境
    UDP组播相关
    eclipse中如何向开源中国(码云)上传代码
    How to copy a java.util.List into another java.util.List
    Windows中.exe程序的启动过程和C/C++运行时库
    GEF调色板中的多级树结构
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8629154.html
Copyright © 2011-2022 走看看