UVA 225 黄金图形(回溯法)详细注释

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=220,O=105;						//O代表中心点(0,0)的坐标 
const char dr[]="ensw";							//东北南西 
const int dx[]={0,1,-1,0};
const int dy[]={1,0,0,-1};
int map[maxn][maxn],vis[maxn][maxn],t,n,k,tot;
char path[22];									//path是用来回溯的数组 
int foot[22];									//n=1总共走1步,n=2总共走3步,n=3总共走6步... 

void init1()
{
	foot[0]=0;
	for(int i=1;i<=20;i++)
	{
		foot[i]=foot[i-1]+i;
	}
}

void init()
{
	memset(map,0,sizeof(map));
	memset(vis,0,sizeof(vis));
	tot=0;
	scanf("%d%d",&n,&k);
	int x,y;
	for(int i=0;i<k;i++)
	{
		scanf("%d%d",&y,&x);
		map[O+x][O+y]=1;				//输入障碍物		
	}	
}

bool judge(int nx,int ny,int cur,int x,int y,int i)
{
	if(abs(nx-O)+abs(ny-O)>foot[n]-foot[cur+1])  return false;
	if(vis[nx][ny]||map[nx][ny]) return false;		//该结点已被访问过或该结点上有障碍
	if(nx==O&&ny==O&&cur!=n-1)   return false;		//不能恰好走第n次经过原点(在第n次前已经经过原点)
	int tx=nx,ty=ny;
	//走出的直线不能经过障碍物
	while(tx!=x)
	{
		tx-=dx[i];
		if(map[tx][y]) return false;
	}
	while(ty!=y)
	{
		ty-=dy[i];
		if(map[x][ty]) return false;
	}
	 
	return true;
}

void dfs(int cur,int x,int y,int d)		//x,y为当前出发点的坐标,cur为回溯法的位置,d为当前的方向 
{
	if(cur==n&&x==O&&y==O)
	{
		tot++;
		for(int i=0;i<n;i++)
		{
			printf("%c",path[i]);
		}
		printf("\n");
		return;
	}
	if(cur==n) return;					//走了n次还没有走到原点,直接回溯 
	for(int i=0;i<4;i++)
	{
		if(i==d||i+d==3) continue;		//不能沿着同一方向或反方向走 
		int nx=x+(cur+1)*dx[i],ny=y+(cur+1)*dy[i]; 
		if(judge(nx,ny,cur,x,y,i))
		{
			vis[nx][ny]=true;
			path[cur]=dr[i];
			dfs(cur+1,nx,ny,i);
			vis[nx][ny]=false;
		}
	}
}

void solve()
{
	dfs(0,O,O,-1);
	printf("Found %d golygon(s).\n\n",tot);
}

int main()
{
	init1();
	scanf("%d",&t);
	while(t--)
	{
		init();
		solve();
	}
	return 0;
}

反思:在回溯法中,找到剪枝的条件很重要,并且回溯的过程可以用过形参记录一个结点的状态。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值