zoukankan      html  css  js  c++  java
  • LOJ 6068「2017 山东一轮集训 Day4」棋盘

    题意

    一个 (n imes n) 的棋盘上面有若干障碍物。

    定义两个棋子可以互相攻击当且仅当这两个棋子的横坐标或纵坐标相等而且中间不能隔着障碍物。(可以隔棋子)

    (q) 次询问,每次询问你要回答在棋盘上摆 (x) 枚棋子最少互相能攻击到的棋子对数。

    ( exttt{Data Range:}1leq nleq 50,1leq qleq 10^4)

    题解

    我咋连套路都不会了啊……

    考虑二分图,将每一行每一列被 # 隔开的小段缩成一个点,对于每个可以放棋子位置像所属横纵坐标的小段连边。

    但是一小段内放了 (x) 个棋子会对答案贡献 (inom{x}{2}),我们要考虑如何最小化这个东西。

    按照蓝书上的套路,考虑将一条边拆成流量为 (1),费用为 (1,2,cdots,x) 的多条边,然后跑单路增广并且记录答案就行了。

    注意到流量的意义就是放棋子的枚数,所以不能按照平常的写法来。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    const ll MAXN=1e4+51,inf=0x7fffffff;
    struct Edge{
        ll to,prev,flow,cost;
    };
    Edge ed[MAXN<<1];
    ll n,source,sink,tot=1,maxFlow,minCost,limit,qcnt,curx;
    char ch[51][51];
    ll last[MAXN],vis[MAXN],dist[MAXN],res[MAXN],back[MAXN];
    ll idx[51][51],idy[51][51],sz[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline void addEdge(ll from,ll to,ll flow,ll cost)
    {
        ed[++tot].prev=last[from];
        ed[tot].to=to;
        ed[tot].flow=flow;
        ed[tot].cost=cost;
        last[from]=tot; 
    }
    inline ll Min(ll x,ll y)
    {
        return x<y?x:y;
    }
    inline bool spfa()
    {
        queue<ll>q;
        ll top,to;
        memset(vis,0,sizeof(vis)); 
        memset(dist,0x3f,sizeof(dist));
        memset(back,0,sizeof(back));
        dist[source]=0,vis[source]=1,q.push(source);
        while(!q.empty())
        {
            top=q.front();
            q.pop(),vis[top]=0;
            for(register int i=last[top];i;i=ed[i].prev)
            {
                to=ed[i].to;
                if(dist[to]>dist[top]+ed[i].cost&&ed[i].flow)
                {
                    dist[to]=dist[top]+ed[i].cost,back[ed[i].to]=i;
                    if(!vis[to])
                    {
                        q.push(to),vis[to]=1;
                    }
                }
            }
        }
        if(dist[sink]!=0x3f3f3f3f)
        {
            return 1;    
        } 
        return 0;
    }
    inline ll MCMF()
    {
        ll flow;
        while(spfa()&&maxFlow<limit)
        {
            for(register int i=back[sink];i;i=back[ed[i^1].to])
            {
                ed[i].flow--,ed[i^1].flow++;
            }
            res[++maxFlow]=(minCost+=dist[sink]);
        }
        return maxFlow;
    }
    int main()
    {
        n=read();
        for(register int i=1;i<=n;i++)
        {
            scanf("%s",ch[i]+1);
            for(register int j=1;j<=n;j++)
            {
                if(ch[i][j]=='.')
                {
                    limit++;
                }
            }
        }
        for(register int i=1;i<=n;i++)
        {
            for(register int j=1;j<=n;j++)
            {
                if(ch[i][j]!='#')
                {
                    idx[i][j]=(ch[i][j]==ch[i][j-1]?idx[i][j-1]:++sink);
                }
            }
        }
        curx=sink;
        for(register int i=1;i<=n;i++)
        {
            for(register int j=1;j<=n;j++)
            {
                if(ch[j][i]!='#')
                {
                    idy[j][i]=(ch[j][i]==ch[j-1][i]?idy[j-1][i]:++sink);
                }
            }
        }
        for(register int i=1;i<=n;i++)
        {
            for(register int j=1;j<=n;j++)
            {
                if(ch[i][j]!='#')
                {
                    sz[idx[i][j]]++,sz[idy[i][j]]++;
                }
            }
        }
        sink++;
        for(register int i=1;i<=curx;i++)
        {
            for(register int j=0;j<sz[i];j++)
            {
                addEdge(source,i,1,j),addEdge(i,source,0,-j);
            }
        }
        for(register int i=curx+1;i<sink;i++)
        {
            for(register int j=0;j<sz[i];j++)
            {
                addEdge(i,sink,1,j),addEdge(sink,i,0,-j);
            }
        }
        for(register int i=1;i<=n;i++)
        {
            for(register int j=1;j<=n;j++)
            {
                if(ch[i][j]=='.')
                {
                    addEdge(idx[i][j],idy[i][j],1,0);
                    addEdge(idy[i][j],idx[i][j],0,0);
                }
            }
        }
        MCMF(),qcnt=read();
        for(register int i=0;i<qcnt;i++)
        {
            printf("%d
    ",res[read()]);
        }
    } 
    
  • 相关阅读:
    大数据介绍
    Android系统手机端抓包方法
    svn warning W205000 :windows下 SVN idea 配置 代理配置
    idea tomcat 启动日志乱码
    翻译 API 一句话API
    git push proxy 取消不掉 can not prox....
    webpack+vue搭建vue项目
    java 多线程
    实时监听 JavaScript改变 input 值 input输入框内容 value 变化实时监听
    leetcode 数组
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13052438.html
Copyright © 2011-2022 走看看