zoukankan      html  css  js  c++  java
  • luoguP4003 无限之环

    题意

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

    对于一条边的描述((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;
    }
    
  • 相关阅读:
    XVIII Open Cup named after E.V. Pankratiev Stage 5: Eastern Grand Prix
    XX Russia Team Open, High School Programming Contest St Petersburg, Barnaul, Tbilisi, Almaty, Kremenchug, November 30, 2019
    2019-2020 ICPC, NERC, Northern Eurasia Finals
    The 2019 China Collegiate Programming Contest Harbin Site
    Southeastern European Regional Programming Contest 2019
    2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)
    2019-2020 Saint-Petersburg Open High School Programming Contest (SpbKOSHP 19)
    hdu6354 Everything Has Changed (圆的相交弧长)
    hdu6341 Problem J. Let Sudoku Rotate (dfs)
    hdu6333 Problem B. Harvest of Apples(组合数+莫队)
  • 原文地址:https://www.cnblogs.com/nofind/p/12111701.html
Copyright © 2011-2022 走看看