POJ 3985 Knight's Problem(bfs+hash+剪枝)






http://poj.org/problem?id=3985








题目大意:

给一个起点和一个终点    给出从个点出发可走的方向(小于等于10)      问最少多少步走到终点














分析:

这个题目是有点厉害了      之前没用过hash表      有现学了一下hash        

推荐篇hash的博客:

http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html



然后说一下思路       关键在于剪枝     怎么剪枝呢       主要是两部分      

首先一定要是从起点向终点终点走     相反走的点舍弃掉     做题的时候想到了     但水平low不会写看了下题解     利用三角形的三边关系就可以判断新的点的走向 

其次    距离起点和终点所在直线较远的点舍弃        到底多远呢      方向一步所走最大值


hash表存下每个点    然后bfs就行了












AC代码:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include<list>
#include <bitset>
#include <climits>
#include <algorithm>
#define gcd(a,b) __gcd(a,b)
#define mset(a,n) memset(a,n,sizeof(a))
#define FIN	freopen("input","r",stdin)
#define FOUT 	freopen("output","w",stdout)
typedef long long LL;
const LL mod=1e9+7;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const int prime=999997;
using namespace std;
int dir[20][2];//         方向数组
int sx,sy,ex,ey;
int n;
int a,b,c;//         直线方程系数
double maxn;
int cnt;
int head[prime];
struct node{//           点
    int tx,ty;
    int step;
};
struct node2{//     链式钱向星存相同Hash地址的点
    int x,y;
    int next;
}edge[1000000];
int Hash(int x,int y){//                求Hash地址
    return (((x<<15)^y)%prime+prime)%prime;
}
int addedge(int u,int x,int y){//       存相同Hash地址的点
    for (int i=head[u];i!=-1;i=edge[i].next)//        之前存在过的点不再计算
        if (edge[i].x==x&&edge[i].y==y) return 0;
    edge[cnt].x=x;
    edge[cnt].y=y;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    return 1;
}
int judge(int x,int y){
    double temp=sqrt(a*a+b*b);
    //    起点、终点、要判断的点构成的三角形三条边
    double A=((sx-x)*(sx-x)+(sy-y)*(sy-y));
    double B=((ex-x)*(ex-x)+(ey-y)*(ey-y));
    double C=((ex-sx)*(ex-sx)+(ey-sy)*(ey-sy));
    if (A+C<B||B+C<A) return 0;//                     向相反方向走
    double length=fabs(a*x+b*y+c)/temp;//             距离直线距离
    if (length<=maxn) return 1;
    return 0;
}
void bfs(){
    queue<node> Q;
    node start;
    start.step=0;
    start.tx=sx;
    start.ty=sy;
    Q.push(start);
    addedge(Hash(sx,sy),sx,sy);
    while (!Q.empty()){
        node temp=Q.front();
        Q.pop();
        if (temp.tx==ex&&temp.ty==ey){
            printf ("%d\n",temp.step);
            return ;
        }
        for (int i=0;i<n;i++){
            node tt=temp;
            tt.tx+=dir[i][0];
            tt.ty+=dir[i][1];
            if(judge(tt.tx,tt.ty)&&addedge(Hash(tt.tx,tt.ty),tt.tx,tt.ty)){
                tt.step++;
                Q.push(tt);
            }
        }
    }
    printf ("IMPOSSIBLE\n");
}
void Init(){
    mset(head,-1); cnt=0;
    scanf ("%d%d%d%d",&sx,&sy,&ex,&ey);
    //      求直线方程(可以用两点式求方程然后化简成标准形式)
    a=sy-ey;
    b=ex-sx;
    c=sx*ey-sy*ex;
    maxn=0;
    scanf ("%d",&n);
    for (int i=0;i<n;i++) {
        scanf ("%d%d",&dir[i][0],&dir[i][1]);
        maxn=max(maxn,sqrt(dir[i][0]*dir[i][0]+dir[i][1]*dir[i][1]));//       偏离直线的最大值
    }
}
int main (){
    //FIN;
    int t;
    scanf ("%d",&t);
    while (t--){
        Init();
        bfs();
    }
    return 0;
}

  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值