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

P4003 无限之环

时间:2019-12-28 16:18:10      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:src   span   而不是   print   set   不难   main   技术   表示   

题意

首先将棋盘黑白染色,要使得棋盘不漏水,当且仅当每个黑点的各个方向的管口都连接上了一个白点的管口。换句话说,我们要让黑点和白点匹配数最大的同时操作次数最小,不难想到最小费用最大流。

对于一条边的描述\((w,c)\)表示容量为\(w\),费用为\(c\)

我们将每个点拆成上下左右四个点,从源点向黑点的所有存在管口的方向连\((1,0)\)的边,白点所有存在管口的方向向汇点连\((1,0)\)的边。

之后对于每对相邻的点,从黑点的一个管口向白点对应管口连\((1,0)\)的边。比如\((i,j)\)\((i-1,j)\)\((i,j)\)是黑点,我们从\((i,j)\)的上方向向\((i-1,j)\)的下方向连边。

现在考虑怎么处理旋转,我们不妨分类讨论。

定义\((i,j,0/1/2/3)\)分别表示\((i,j)\)的表示上下左右的点。

1.只有一个管口的:
以下图为例,其他同理:
技术图片
顺时针旋转\(90\)度:
此时管口从上移到了右。
如果这是个黑点,那么从\((i,j,0)\)\((i,j,3)\)\((1,1)\)的边,这表示从\(S\)流向\((i,j,0)\)的容量为\(1\)的流可以通过这条边改变方向,与\((i,j+1,2)\)匹配,而不是\((i-1,j,1)\)
如果这是个白点,我们从从\((i,j,3)\)\((i,j,0)\)\((1,1)\)的边,这表示\((i,j,3)\)可以匹配后通过这条边对汇点贡献流量。

下面所有默认\((i,j)\)是黑点。(是白点就将起点和终点反过来)

逆时针旋转\(90\)度:
同理,连边\(((i,j,0),(i,j,2),1,1,)\)

旋转\(180\)度:
同理,连边\(((i,j,0),(i,j,1),1,1)\)

2.两个管口的:
因为直的禁止旋转,我们只需要考虑\(L\)型的即可。

仍只以下图为例,其他同理:
技术图片
顺时针旋转\(90\)度:
此时向右的管口没有消失,而向上的变为了向下的,因此从\((i,j,0)\)\((i,j,1)\)\((1,1)\)的边。

逆时针旋转\(90\)度:
此时向上的管口没有消失,而向右的变为了向左的,因此从\((i,j,3)\)\((i,j,2)\)\((1,1)\)的边。

旋转\(180\)度:
这时管从上右变为了左下,费用为\(2\),我们发现我们之前连的两条边正好产生了这个作用。

3.三个管口的
仍然以下图为例。
技术图片

上面两个要是理解了,这个就很快知道了,于是只给出连边。

顺时针旋转\(90\)度:
\((i,j,2)\)\((i,j,1)\)\((1,1)\)的边。
逆时针旋转\(90\)度:
\((i,j,3)\)\((i,j,1)\)\((1,1)\)的边。
旋转\(180\)度:
\((i,j,0)\)\((i,j,1)\)\((1,2)\)的边。

code:

#include<bits/stdc++.h>
using namespace std;
#define re register
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
const int maxn=2010;
const int inf=1e9;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
int n,m,tot=1,cnt_edge=1,S,T,sum;
int head[maxn*5],dis[maxn*5],col[maxn*5];
int a[maxn][maxn];
int id[maxn][maxn][5];//0->up,1->down,2->left,3->right.
bool vis[maxn*5];
struct edge{int to,nxt,flow,cost;}e[maxn*50];
inline int read()
{
    char c=getchar();re int res=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
inline int change(int k)
{
    re int op=2333;
    if(k==0)op=0;
    if(k==1)op=3;
    if(k==2)op=1;
    if(k==3)op=2;
    return op;
}
inline void add(int u,int v,int w,int c)
{
    e[++cnt_edge].nxt=head[u];
    head[u]=cnt_edge;
    e[cnt_edge].to=v;
    e[cnt_edge].flow=w;
    e[cnt_edge].cost=c;
}
inline void addflow(int u,int v,int w,int c)
{
    if(!col[u]&&u!=S&&v!=T)swap(u,v);//edge:: black->white.
    add(u,v,w,c);add(v,u,0,-c);
}
inline void solve(int x,int y,int type)
{
    if(!type||type==5||type==10||type==15)return;
    int num=0;
    for(int i=0;i<4;i++)if((type>>i)&1)num++;
    if(num==1)
    {
        if(type==1)
        {
            re int turn=0;
            addflow(id[x][y][turn],id[x][y][3],1,1);
            addflow(id[x][y][turn],id[x][y][2],1,1);
            addflow(id[x][y][turn],id[x][y][1],1,2);
            return;
        }
        if(type==2)
        {
            re int turn=3;
            addflow(id[x][y][turn],id[x][y][1],1,1);
            addflow(id[x][y][turn],id[x][y][0],1,1);
            addflow(id[x][y][turn],id[x][y][2],1,2);
            return;
        }
        if(type==4)
        {
            re int turn=1;
            addflow(id[x][y][turn],id[x][y][2],1,1);
            addflow(id[x][y][turn],id[x][y][3],1,1);
            addflow(id[x][y][turn],id[x][y][0],1,2);
            return;
        }
        if(type==8)
        {
            re int turn=2;
            addflow(id[x][y][turn],id[x][y][0],1,1);
            addflow(id[x][y][turn],id[x][y][1],1,1);
            addflow(id[x][y][turn],id[x][y][3],1,2);
            return;
        }
    }
    if(num==2)
    {
        if(type==3)
        {
            addflow(id[x][y][0],id[x][y][1],1,1);
            addflow(id[x][y][3],id[x][y][2],1,1);
            return;
        }
        if(type==6)
        {
            addflow(id[x][y][3],id[x][y][2],1,1);
            addflow(id[x][y][1],id[x][y][0],1,1);
            return;
        }
        if(type==9)
        {
            addflow(id[x][y][2],id[x][y][3],1,1);
            addflow(id[x][y][0],id[x][y][1],1,1);
            return;
        }
        if(type==12)
        {
            addflow(id[x][y][1],id[x][y][0],1,1);
            addflow(id[x][y][2],id[x][y][3],1,1);
            return;
        }
    }
    if(num==3)
    {
        if(type==7)
        {
            addflow(id[x][y][0],id[x][y][2],1,1);
            addflow(id[x][y][1],id[x][y][2],1,1);
            addflow(id[x][y][3],id[x][y][2],1,2);
            return;
        }
        if(type==11)
        {
            addflow(id[x][y][2],id[x][y][1],1,1);
            addflow(id[x][y][3],id[x][y][1],1,1);
            addflow(id[x][y][0],id[x][y][1],1,2);
            return;
        }
        if(type==13)
        {
            addflow(id[x][y][1],id[x][y][3],1,1);
            addflow(id[x][y][0],id[x][y][3],1,1);
            addflow(id[x][y][2],id[x][y][3],1,2);
            return;
        }
        if(type==14)
        {
            addflow(id[x][y][3],id[x][y][0],1,1);
            addflow(id[x][y][2],id[x][y][0],1,1);
            addflow(id[x][y][1],id[x][y][0],1,2);
            return;
        }
    }
}
inline bool spfa()
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    deque<int>q;
    q.push_front(S);dis[S]=0;vis[S]=1;
    while(!q.empty())
    {
        re int x=q.front();q.pop_front();vis[x]=0;
        for(re int i=head[x];i;i=e[i].nxt)
        {
            re int y=e[i].to;
            if(dis[y]>dis[x]+e[i].cost&&e[i].flow>0)
            {
                dis[y]=dis[x]+e[i].cost;
                if(!vis[y])
                {
                    if(q.empty()||dis[y]>dis[q.front()])q.push_back(y);
                    else q.push_front(y);
                    vis[y]=1;
                }
            }
        }
    }
    return dis[T]!=0x3f3f3f3f;
}
int dfs(int x,int lim)
{
    vis[x]=1;
    if(x==T||lim<=0)return lim;
    re int res=lim;
    for(re int i=head[x];i;i=e[i].nxt)
    {
        re int y=e[i].to;
        if(dis[y]!=dis[x]+e[i].cost||e[i].flow<=0||vis[y])continue;
        re int tmp=dfs(y,min(res,e[i].flow));
        res-=tmp;
        e[i].flow-=tmp,e[i^1].flow+=tmp;
        if(res<=0)break;
    }
    return lim-res;
}
inline pii Dinic()
{
    re int res=0,cost=0;
    while(spfa())
    {
        re int flow=dfs(S,inf);
        while(flow>0)
        {
            res+=flow,cost+=flow*dis[T];
            memset(vis,0,sizeof(vis));
            flow=dfs(S,inf);
        }
    }
    return mkp(res,cost);
}
int main()
{
    n=read(),m=read();
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
            a[i][j]=read();
    S=1;
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
            for(re int k=0;k<4;k++)
            {
                id[i][j][k]=++tot;
                col[tot]=!((i+j)&1);
            }
    T=tot+1;
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
            for(re int k=0;k<4;k++)
            {   
                if(!((a[i][j]>>k)&1))continue;
                sum++;
                re int op=change(k);
                if(!((i+j)&1))addflow(S,id[i][j][op],1,0);
                else addflow(id[i][j][op],T,1,0);
            }
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
        {
            if(i<n)addflow(id[i][j][1],id[i+1][j][0],1,0);
            if(j<m)addflow(id[i][j][3],id[i][j+1][2],1,0);
        }
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
            solve(i,j,a[i][j]);
    pii ans=Dinic();
    printf("%d",ans.fir==(sum>>1)?ans.sec:-1);
    return 0;
}

P4003 无限之环

标签:src   span   而不是   print   set   不难   main   技术   表示   

原文地址:https://www.cnblogs.com/nofind/p/12111701.html

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