ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

UVA10572 Black & White 题解

2022-05-03 09:01:19  阅读:158  来源: 互联网

标签:wedge 颜色 连通性 格子 int 题解 && UVA10572 White


插头 DP

Statement

UVA10572 Black & White - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Solution

因为相邻格子连通性取决于颜色而不取决于几联通,所以我们需要记录轮廓线上方 \(m\) 个格子的颜色和连通性

注意区分颜色和连通性的区别,颜色相同不一定联通

同时注意到题面的特殊限制,所以需要保存 \((i-1,j-1)\) 的颜色

连通性需要使用广义括号表示法/最小表示法表示,这里采用最小表示法

联通状态最多有 8 种不同的,直接上 8 进制即可。

即,设 \(f(i,j,sta,col,cp)=val\) 表示正在涂色 \((i,j)\) ,轮廓线连通性 $sta $ ,颜色 \(col\) ,\((i-1,j-1)\) 颜色 \(cp\) 的方案数

考虑转移,设 \(u,l,lu\) 分别表示 \((i,j)\) 颜色是否和 上面/左边/左上 格子颜色相同

容易 \(O(1)\) 推知下一次的 \(col^{\prime},cp^{\prime}\) ,关键在于连通性,解码 \(sta\to a\)

  • \(u\wedge l\) ,合并联通块 \(a[j-1],a[j]\) ,把所有 \(a[x]=a[j]\) ,刷成 \(a[x]=a[j-1]\)
  • \(u\wedge !l\) ,连通性没有变化
  • \(!u\wedge l\) ,\(a[j]=a[j-1]\)
  • \(!u\wedge !l\) ,自立山门,\(a[j]=mx+1\)

重新编码的时候注意要满足最小表示法。

显然,如果 \(u\wedge l\wedge lu\) ,那就直接 G 了

考虑什么时候也会 GG:

  • \(i==n \wedge j==m\wedge !l\wedge !u\wedge lu\)
  • \(!u\) 且 \(u\) 在轮廓线上独立成一个连通块 且 轮廓线上存在其他任意个与 \(u\) 颜色相同但的格子
  • \(!u\) 且轮廓线上不存在一个与 \(u\) 颜色相同的格子 且 \((i,j)\) 不是棋盘最后两个格子

第二条:可以考虑试填法,\((i,j-1)\) 位必然和 \((i,j)\) 相同。因为如若不相同,那么 \((i-1,j-1)\) 必然与 \((i,j)\) 相同,卡死了。同时 \((i-1,j+1)\) 位也和 \((i,j)\) 相同。因为其他格子和 \((i-1,j)\) 连通性都不同,容易发现 \((i-1,j)\) 被孤立,GG

第三条:很显然,此时轮廓线下方格子应该全部都涂黑

输出方案的话在 DP 过程中记录一个 pre 就可以了

Code

小记:写了一个晚上,c。下午 4:30 左右开始思考(穿插看 ppt 和题解),5:30 大致理解。吃完饭 6:30 开始按照自己的理解写,写到 \(9:00\) ,死活不对,开始看题解代码

漏掉的细节:

  • 边界条件应该直接认为是不同颜色,不能认为是相同颜色
  • 由于直接认定为不同,所以并不需要像【模板】那样,开始之前 \(que<<=3\)
  • 虽然你有 hash_map ,你可以直接使用十进制编码,但是不管什么进制,每次在最小表示法的时候一定要重编号(为啥会认为十进制就不用重编号...
  • 取答案的时候不要直接 判断都不上/乱判断 直接取(为啥会判断成 \(mx==0\) 才行。。。)
  • 请认真分析什么时候会 GG ,不要 yy 过头
#include<bits/stdc++.h>
#define bit(x) (1<<(x))
using namespace std;
typedef long long ll;
const int mod = 233333;
const int M = mod + 5;
const int N = 20;

int read(){
	int s=0,w=1; char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
	return s*w;
}

int a[N],num[N],pre[100][mod+5];
char mp[N][N],op[100][mod+5];
int T,n,m,now;

struct Hash_map{
	int nex[M],head[M];
	int sta[M],col[M],val[M];//二进制表示 col ,八进制表示 sta
	int siz;
	
	void clear(){
		memset(head,0,sizeof(head));
		siz=0;
	}
	void insert(int s,int c,int v,int id,int fa,char o){
		for(int i=head[s%mod];i;i=nex[i])
			if(sta[i]==s&&col[i]==c)
				return val[i]+=v,void();
		sta[++siz]=s,col[siz]=c,val[siz]=v;
		pre[id][siz]=fa,op[id][siz]=o;
		nex[siz]=head[s%mod],head[s%mod]=siz; 
	}
}dp[2];

void decode(int s){//解码
	for(int i=m-1;~i;--i)
		a[i]=s&7,s>>=3;
}
int encode(){//最小表示法
	memset(num,-1,sizeof(num));
	int k=-1,res=0;
	for(int i=0;i<m;++i){
		if(num[a[i]]==-1)num[a[i]]=++k;
		res=(res<<3)|num[a[i]];
	}
	return res;
}
void change(int x,int y){//刷颜色
	for(int i=0;i<m;++i)
		if(a[i]==x)a[i]=y;
}
void DP(int i,int j,int c){
	for(int k=1;k<=dp[now].siz;++k){
		int cc=dp[now].col[k];
		int u=i?(cc>>j&1)==c:0;
		int l=j?(cc>>(j-1)&1)==c:0;//边界直接认为不相同
		int lu=(cc>>m)==c;// 二进制第 m 位存放 (i-1,j-1)
		if(u&&l&&lu)continue;
		if(i==n-1&&j==m-1&&!u&&!l&&lu)continue;
		decode(dp[now].sta[k]);
		if(i&&!u){
			int s1=0,s2=0;
			for(int t=0;t<m;++t)
				s1+=a[t]==a[j],s2+=((cc>>t&1)!=c);
            //s1:连通性相同格子个数, s2: 与 u 颜色相同个数
			if(s1==1){
				if(s2>1)continue;
				if(i<n-1||j<m-2)continue;
			}
		}
		
		if(u&&l){
			if(a[j]!=a[j-1])
				change(a[j],a[j-1]);
		}else if(!u&&l)a[j]=a[j-1];
		else if(!u&&!l)a[j]=m;
		if(cc&(1<<j))cc|=1<<m; else cc&=~(1<<m);
		if(c)cc|=1<<j; else cc&=~(1<<j);
		
		dp[now^1].insert(encode(),cc,dp[now].val[k],i*m+j,k,c?'#':'o');
	}
}
void print(int k){
	for(int i=n-1;i>=0;--i)
		for(int j=m-1;j>=0;--j)
			mp[i][j]=op[i*m+j][k],
			k=pre[i*m+j][k];
	for(int i=0;i<n;++i)puts(mp[i]);
}

signed main(){
	T=read();
	while(T--){
		n=read(),m=read();
		memset(mp,0,sizeof(mp));
		for(int i=0;i<n;++i)
			for(int j=0;j<m;++j)
				scanf(" %c",&mp[i][j]);
		now=0,dp[0].clear(),dp[0].insert(0,0,1,0,0,0);
		for(int i=0;i<n;++i)
			for(int j=0;j<m;++j){
				dp[now^1].clear();
				if(mp[i][j]!='#')DP(i,j,0);
				if(mp[i][j]!='o')DP(i,j,1);
				now^=1;
			}
		int ans=0,k;
		for(int i=1;i<=dp[now].siz;++i){
			int mx=0;
			decode(dp[now].sta[i]);
			for(int j=0;j<m;++j)
				mx=max(mx,a[j]);
			if(mx>1)continue;
			ans+=dp[now].val[i];
			k=i;
		}
		printf("%d\n",ans);
		if(ans)print(k);
		puts("");//UVA 神奇要求
	}	
	return 0;
}

标签:wedge,颜色,连通性,格子,int,题解,&&,UVA10572,White
来源: https://www.cnblogs.com/wyb-sen/p/16217646.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有