BZOJ1501: [NOI2005]智慧珠游戏

精确覆盖问题,用dancing links求解。

打常量表比较麻烦。

const int f[60][12]={
	0,3,0,0,0,1,1,0,0,0,0,0,
	0,3,0,0,0,1,1,1,0,0,0,0,
	0,3,0,0,1,0,1,1,0,0,0,0,
	0,3,0,1,1,0,1,1,0,0,0,0,
	1,4,0,0,0,1,0,2,0,3,0,0,
	1,4,0,0,1,0,2,0,3,0,0,0,
	2,4,0,0,0,1,0,2,1,0,0,0,
	2,4,0,0,0,1,0,2,1,2,0,0,
	2,4,0,0,0,1,1,0,2,0,0,0,
	2,4,0,0,0,1,1,1,2,1,0,0,
	2,4,0,0,1,0,1,1,1,2,0,0,
	2,4,0,0,1,0,2,0,2,1,0,0,
	2,4,0,1,1,1,2,0,2,1,0,0,
	2,4,0,2,1,0,1,1,1,2,0,0,
	3,4,0,0,0,1,1,0,1,1,0,0,
	4,5,0,0,0,1,0,2,1,0,2,0,
	4,5,0,0,0,1,0,2,1,2,2,2,
	4,5,0,0,1,0,2,0,2,1,2,2,
	4,5,0,2,1,2,2,0,2,1,2,2,
	5,5,0,0,0,1,0,2,0,3,1,1,
	5,5,0,0,0,1,0,2,0,3,1,2,
	5,5,0,0,1,0,1,1,2,0,3,0,
	5,5,0,0,1,0,2,0,2,1,3,0,
	5,5,0,1,1,0,1,1,1,2,1,3,
	5,5,0,1,1,0,1,1,2,1,3,1,
	5,5,0,1,1,1,2,0,2,1,3,1,
	5,5,0,2,1,0,1,1,1,2,1,3,
	6,5,0,0,0,1,0,2,1,0,1,2,
	6,5,0,0,0,1,1,0,2,0,2,1,
	6,5,0,0,0,1,1,1,2,0,2,1,
	6,5,0,0,0,2,1,0,1,1,1,2,
	7,5,0,0,0,1,0,2,1,0,1,1,
	7,5,0,0,0,1,0,2,1,1,1,2,
	7,5,0,0,0,1,1,0,1,1,1,2,
	7,5,0,0,0,1,1,0,1,1,2,0,
	7,5,0,0,0,1,1,0,1,1,2,1,
	7,5,0,0,1,0,1,1,2,0,2,1,
	7,5,0,1,0,2,1,0,1,1,1,2,
	7,5,0,1,1,0,1,1,2,0,2,1,
	8,5,0,0,0,1,0,2,1,2,1,3,
	8,5,0,0,0,1,1,1,1,2,1,3,
	8,5,0,0,1,0,1,1,2,1,3,1,
	8,5,0,0,1,0,2,0,2,1,3,1,
	8,5,0,1,0,2,0,3,1,0,1,1,
	8,5,0,1,1,0,1,1,2,0,3,0,
	8,5,0,1,1,1,2,0,2,1,3,0,
	8,5,0,2,0,3,1,0,1,1,1,2,
	9,5,0,1,1,0,1,1,1,2,2,1,
	10,5,0,0,0,1,1,1,1,2,2,2,
	10,5,0,0,1,0,1,1,2,1,2,2,
	10,5,0,1,0,2,1,0,1,1,2,0,
	10,5,0,2,1,1,1,2,2,0,2,1,
	11,5,0,0,0,1,0,2,0,3,1,0,
	11,5,0,0,0,1,0,2,0,3,1,3,
	11,5,0,0,0,1,1,0,2,0,3,0,
	11,5,0,0,0,1,1,1,2,1,3,1,
	11,5,0,0,1,0,1,1,1,2,1,3,
	11,5,0,0,1,0,2,0,3,0,3,1,
	11,5,0,1,1,1,2,1,3,0,3,1,
	11,5,0,3,1,0,1,1,1,2,1,3
};
#include<cstdio>
#include<cstdlib>
#include<new>
#define FOR(i,s,t)\
	for(ptr i=(s)->t;i!=(s);i=i->t)
const int N=3300;
const int M=67;
char s[16][16];
int q[M],v[12];
typedef struct node*ptr;
struct node{
	ptr l,r,u,d;
	int x,y;
	node(){l=r=u=d=this;}
	node(ptr i,ptr j){
		l=i,r=i->r,u=j,d=j->d;
		x=i->x,++q[y=j->y];
		l->r=r->l=u->d=d->u=this;
	}
}e[N*6],r[N],c[M];
ptr o=e+1,h=e,t=e;
int cal(int i,int j){return i*(i+1)/2+j;}
int xpos(int k){
	for(int i=1;;++i)
		if(i*(i+1)/2>k)return i-1;
}
int ypos(int k){
	return k-xpos(k)*(xpos(k)+1)/2;
}
void ins(int i,int j,int k){
	int s=k*55+cal(i,j);
	new(o++)node(r+s,c+*f[k]+55);
	for(int l=1;l<=f[k][1];++l)
		new(o++)node(r+s,c+cal(i+f[k][l*2],j+f[k][l*2+1]));
}
void rem(int k){
	c[k].l->r=c[k].r,c[k].r->l=c[k].l;
	FOR(i,c+k,d)FOR(j,i,l)
		j->u->d=j->d,j->d->u=j->u,--q[j->y];
}
void res(int k){
	c[k].r->l=c[k].l->r=c+k;
	FOR(i,c+k,u)FOR(j,i,l)
		++q[(j->u->d=j->d->u=j)->y];
}
void dfs(int z){
	static int u[12];
	if(h->l==h){
		for(int a=0;a!=12;++a){
			int i=xpos(u[a]%55);
			int j=ypos(u[a]%55);
			int k=u[a]/55;
			for(int l=1;l<=f[k][1];++l)
				s[f[k][l*2]+i][f[k][l*2+1]+j]=*f[k]+65;
		}
		for(int i=0;i!=10;++i)puts(s[i]);
		exit(0);
	}
	int s=h->l->y;
	FOR(i,h,l)
		if(q[s]>q[i->y])s=i->y;
	rem(s);
	FOR(i,c+s,d){
		u[z]=i->x;
		FOR(j,i,r)rem(j->y);
		dfs(z+1);
		FOR(j,i,l)res(j->y);
	}
	res(s);
}
bool jud(const int*f,int i,int j,int k){
	for(int l=1;l<=f[1];++l)
		if(s[f[l*2]+i][f[l*2+1]+j]!=k)return 0;
	return 1;
}
int main(){
	for(int i=0;i!=10;++i){
		scanf("%s",s[i]);
		for(int j=0;s[i][j];++j)
			if(s[i][j]!=46)v[s[i][j]-65]=1;
	}
	for(int i=0;i!=N;++i)
		(t=((t->d=r+i)->u=t)->d)->x=i;
	t=((t->d=h)->u=t)->d;
	for(int i=M-1;~i;--i)
		(t=((t->l=c+i)->r=t)->l)->y=i;
	t=((t->l=h)->r=t)->l;
	for(int i=0;i!=10;++i)
		for(int j=0;s[i][j];++j)
			for(int k=0;k!=60;++k)
				if(jud(f[k],i,j,v[*f[k]]?*f[k]+65:46))ins(i,j,k);
	for(int i=0;i!=N;++i)
		r[i].l->r=r[i].r,r[i].r->l=r[i].l;
	dfs(0),puts("No solution");
}

转载于:https://www.cnblogs.com/f321dd/p/5496480.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值