ABC274G题解

这是一个比较经典的网络流的建模。

首先我们可以横着和竖着给原图编两遍号,能够一次照到的编号相同。

以样例一为例:

. . .
. # .
. . .

先横着编号:

1 1 1
2 # 3
4 4 4

再竖着编号:

5 6 8
5 # 8
5 7 8

然后我们将横着的图连源点,竖着的图连汇点,横着的与竖着的之间编号相对位置对应的也要连边,即 \(1\)\(5\)\(2\)\(6\)\(3\)\(7\)\(4\)\(8\),然后直接跑一边最大流即可。

Code

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+5;
const int INF=0x7f7f7f7f;

// char buf[1<<21],*p1=buf,*p2=buf;
// #define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); }
    while(isdigit(ch))
        x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return x*f;
}

struct edge
{
    int to,nxt,flow;
}e[MAXN<<1];

int head[MAXN],cnt=1;

inline void add(int x,int y,int f)
{
    e[++cnt].to=y;
    e[cnt].flow=f;
    e[cnt].nxt=head[x];
    head[x]=cnt;
    return;
}

inline void addn(int x,int y,int f)
{
    add(x,y,f);
    add(y,x,0);
    return;
}

int dep[MAXN],gap[MAXN];
int n,m,s,t;

inline void bfs()
{
    queue<int>q;
    memset(dep,0,sizeof(dep));
    memset(gap,0,sizeof(gap));
    dep[t]=1;
    gap[1]=1;
    q.push(t);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(dep[y]) continue;
            q.push(y);
            dep[y]=dep[x]+1;
            gap[dep[y]]++;
        }
    }
    return;
}

int maxflow,cur[MAXN];

inline int dfs(int x,int flow)
{
    if(x==t)
    {
        maxflow+=flow;
        return flow;
    }
    int used=0;
    for(int i=cur[x];i;i=e[i].nxt)
    {
        cur[x]=i;
        int y=e[i].to,f=e[i].flow;
        if(dep[x]==dep[y]+1 && f)
        {
            int w=dfs(y,min(f,flow-used));
            e[i].flow-=w;
            e[i^1].flow+=w;
            used+=w;
            if(used==flow) return used;
        }
    }
    gap[dep[x]]--;
    if(!gap[dep[x]]) dep[s]=n*m*2+3;
    dep[x]++,gap[dep[x]]++;
    return used;
}

inline int Isap()
{
    maxflow=0;
    bfs();
    while(dep[s]<=n*m*2+1)
        memcpy(cur,head,sizeof(cur)),dfs(s,INF);
    return maxflow;
}

char c[305][305];
int id1[305][305],id2[305][305];

int main()
{
    n=read(),m=read();
    s=0,t=n*m*2+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>c[i][j];
    int tot=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(c[i][j]=='#') continue;
            id1[i][j]=++tot;
            int k=j+1;
            while(c[i][k]=='.') id1[i][k]=tot,k++;
            j=k;
        }
    int mid=tot;
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++)
        {
            if(c[i][j]=='#') continue;
            id2[i][j]=++tot;
            int k=i+1;
            while(c[k][j]=='.') id2[k][j]=tot,k++;
            i=k;
        }
    for(int i=1;i<=mid;i++) addn(s,i,1);
    for(int i=mid+1;i<=tot;i++) addn(i,t,1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            addn(id1[i][j],id2[i][j],1);
    printf("%d\n",Isap());
    return 0;
}
posted @ 2022-10-23 12:54  Code_AC  阅读(62)  评论(0编辑  收藏  举报