51nod1581 摆放骨牌

2 篇文章 0 订阅
1 篇文章 0 订阅
题目来源:  CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注

现在要用1×2的骨牌铺满n×m 方格中空的地方。

这些骨牌只能铺在空的地方并且不能重叠。

如果有唯一解,输出方案,如果没有解或者有多解输出Not unique

样例解释:

第一个样例中,有两种解:

 
  
 
1
2
3
< >^
^*v
v < >
 

 
  
 
1
2
3
^ < >
v*^
< >v
 

所以答案是Not unique。


Input
单组测试数据。
第一行有两个整数 n 和m (1≤n,m≤2000).
接下来n行,每一行有m个字符,字符'.'表示空格子,'*'表示已经满的格子。
Output
如果没有解或者多解输出Not unique。
如果是唯一解,就输出那个解。用"<>" 表示横放的骨牌,用"^v"表示竖放的骨牌。看样例获得更多信息。
Input示例
样例输入1
3 3
...
.*.
...
样例输入2
4 4
..**
*...
*.**
....
Output示例
样例输出1
Not unique
样例输出2
<>**
*^<>
*v**
<><>

题解:

有点拓扑排序的味道

找到唯一能够覆盖的,然后盖上去,找找到下一个度数为1的。

然后搞一搞就好了。


代码(有两个点会超时,谨慎食用):

#include <algorithm>
#include <string.h>
#include <stdio.h>
using namespace std;
struct aaa{
	int l1,r1;
}q[4000001];
char s1[5],s2[5],a[2002][2002],ans[2002][2002];
int b[2002][2002],bb[5],cc[5];
void bfs(int ll,int rr){
	int l=0,r=1,t,k,i,ii,x,y,u,v;
	q[1].l1=ll;q[1].r1=rr;
	while(l<r){
		l++;
		u=q[l].l1;v=q[l].r1;
		b[u][v]=0;
		for(i=1;i<=4;i++){
			x=u+bb[i];y=v+cc[i];
			if(b[x][y]==0)continue;
			b[x][y]=0;
			ans[u][v]=s1[i];ans[x][y]=s2[i];
				for(ii=1;ii<=4;ii++){
					t=x+bb[ii];k=y+cc[ii];
					if(b[t][k])b[t][k]--;
					if(b[t][k]==1){
						r++;
						q[r].l1=t;q[r].r1=k;
					}
				} 
		}
	}
} 
int main(){
	int n,m,i,j,x,y,flag=0,ii;
	char s[10000];
	s1[1]='<';s1[2]='>';s1[3]='^';s1[4]='v';
	s2[1]='>';s2[2]='<';s2[3]='v';s2[4]='^';
	bb[1]=0;bb[2]=0;bb[3]=1;bb[4]=-1;
	cc[1]=1;cc[2]=-1;cc[3]=0;cc[4]=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		scanf("%s",&s);
		for(j=1;j<=m;j++)a[i][j]=s[j-1];
	}
	for(i=1;i<=n;i++)
	 for(j=1;j<=m;j++)
	  if(a[i][j]=='.'){
	  	for(ii=1;ii<=4;ii++){
	  		x=i+bb[ii];y=j+cc[ii];
	  		if(a[x][y]=='.')b[i][j]++;
		  }
	  }
	for(i=1;i<=n;i++)
	 for(j=1;j<=m;j++)
	  if(b[i][j]==1)bfs(i,j);
	for(i=1;i<=n;i++)
	 for(j=1;j<=m;j++)
	  if(a[i][j]=='.'&&ans[i][j]==0){
	  	flag=1;
	  	break;
	  }
	if(flag)printf("Not unique");
	 else{
	 	 for(i=1;i<=n;i++)
	 	  for(j=1;j<=m;j++)
	 	   if(!ans[i][j])ans[i][j]='*';
	 	 for(i=1;i<=n;i++){
		   for(j=1;j<=m;j++)printf("%c",ans[i][j]);
		   printf("\n");
	}
	 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值