(枚举)洛谷P1556幸福的路

博客分析了洛谷P1556题目的解题思路,强调枚举在解决此类问题中的关键作用。通过枚举所有可能的牛的顺序,结合剪枝优化算法,确保移动符合正向(东南西北)要求。文章还介绍了如何将问题转化为判断题,并提供了将坐标映射到单位向量的方法来检查路径是否正确。
摘要由CSDN通过智能技术生成

一、算法分析

暴力和枚举几乎是一个同义词,看到数据范围,n最大只有10,这就几乎等于直接告诉你要进行枚举了。紫书上有一道例题。

提供了生成排列的思路。枚举出所有到达牛的顺序,这样对于每次移动,我们只需要关心当前牛和下一头牛之间的关系(如果不剪枝的话)再在必要的地方进行剪枝(剪枝显然是要剪的)。

通常解题时,如果正着做不好做,就反着做。如果条件不够,就发掘隐含条件。如果情境复杂,就建模转化。如果计算复杂,就分类计算。如果规模复杂,可以考虑分治。如果不好入手,可以先构造再判断。如果不好构造,可以暴力枚举所有情况再判断。

本题可以采用枚举,将“解答题”转化为“判断题”。判断时的方案如下:
要求所有路径都必须是(正东南西北),我们可以认为东南西北是一个xOy坐标系,然后将两点坐标相减,得到一个方向向量,再将这个向量分别向x轴和y轴进行映射,也就是相当于将其移到原点再正交分解,同时转化为单位向量。如果两次映射的结果均不等于0,则说明这个移动不是正向的,需要抛弃。

二、代码及注释

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=15;
int n;
int ans;
int posx[maxn];
int posy[maxn];                               //各个点的x和y坐标,读入了之后就不要再变动了 
int pl[maxn];                                 //排列的可能,直接用next_permutation
void meijv(){
	int lst_dx=0;                               //上一个方向向量 
	int lst_dy=0;
	for(int i=-1;i<n;i++){
		int x,y;                                  //当前点
		int dx,dy;                                //方向向量
		int xp,yp;                                //下一个点
		if(i==-1){                                //起点 
			x=0;
			y=0;
		} 
		else{
			x=posx[pl[i]];
			y=posy[pl[i]];
		}
		if(i==n-1){                               //最后一个点 
			xp=0;
			yp=0;
		}
		else{
			xp=posx[pl[i+1]];
			yp=posy[pl[i+1]];
		}
		dx=xp-x;
		if(dx!=0) dx/=abs(dx);
		dy=yp-y;
		if(dy!=0) dy/=abs(dy);
		if(dx && dy) return;                         //如果不走四个正向
		if(i==-1){
		  lst_dx=dx;
		  lst_dy=dy;
			continue;
	  }
		if(dx==lst_dx && dy==lst_dy) return;
		lst_dx=dx;
		lst_dy=dy;
	}
	ans++;
}
int main(){

  cin>>n;
	for(int i=0;i<n;i++) cin>>posx[i]>>posy[i]; 
  for(int i=0;i<n;i++) pl[i]=i;               //起始排列 
  
  do{                                         //枚举所有可能,依次进行检查 
		meijv();
	}while(next_permutation(pl,pl+n));          //next_permutation自带返回值,生成完所有排列后跳出 
  
  cout<<ans;
  
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值