zoj 1158 Treasure Hunt

本文介绍了一个基于计算几何原理的寻宝游戏算法实现。玩家需要通过开凿最少数量的门来穿越由直线构成的墙壁到达宝藏所在的位置。文章详细解释了如何通过数学计算判断宝藏与各墙壁的位置关系,并寻找最优路径。
输入
第一行输入一个正数N(N<10)表示测试数据组数
每组测试数据的第一行是一个整数n(0<=n<=30),代表了墙的个数,随后的n行里每行有四个整数x1,x2,y1,y2,这四个数分别是代表一个墙的两个端点的坐标。外围的正方形四个顶点固定在(0,0)(0,100)(100,0)(100,100)这四堵个墙不在上面的n个数里。注意,不能在两个线的交点处开凿门。
数据保证任意两个中间墙的交点不在四周的墙上。
输完所有的墙后,输入两个数,x,y(可能不是整数),表示宝藏的坐标。
输出

输出最少需要开凿的门的个数 

#include <stdio.h>
#include <stdlib.h>
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)
#define ZERO 1e-4
 struct interior 
 {
   int x1, y1, x2, y2;
 }inner[40];
 struct sides
 {
  int a, b, c;
 }side[40];
 struct exterior
 {
  int x, y;
 }outer[40];
 //判断宝藏与内墙位置 
 void judge(struct interior w, struct sides *e)
 {
   e->a = w.y2 -w.y1;
   e->b = w.x1 -w.x2;
   e->c = w.x2*w.y1 - w.x1*w.y2;
 }
int main()
{
  //file_r("1.in");
  //file_w("2.out"); //文件出入结束是在最上面的。。 
  int i, j, k;
  int x1, y1, x2, y2;
  int n;
  double tx, ty;
  int s1[40];
  int N;
  scanf("%d",&N);
  while(N--)
  {
    scanf("%d",&n);
    // 外墙的端点坐标
    outer[0].x = 0;  outer[0].y = 0;
    outer[1].x = 0;  outer[1].y = 100;
    outer[2].x = 100;  outer[2].y = 100;
    outer[3].x = 100;  outer[3].y = 0;
    int sp = 3;
    for(i=0; i<n; i++)
    {
     scanf("%d%d%d%d",&x1, &y1, &x2, &y2);
     outer[++sp].x = x1;  //墙的端点坐标 
     outer[sp].y = y1;
     outer[++sp].x = x2;
     outer[sp].y = y2;
     inner[i].x1 = x1;
     inner[i].y1 = y1;
     inner[i].x2 = x2;
     inner[i].y2 = y2; 
    } 
    scanf("%lf%lf",&tx, &ty);
    double side0;
    for(i=0; i<n; i++)
    {
      judge(inner[i], &side[i]);
      side0 = side[i].a *tx +side[i].b*ty + side[i].c;
      if(side0>ZERO) s1[i] = 1;
      else if(side0<ZERO) s1[i] = -1;
      else s1[i] = 0;
    }
    int door;
    int minDoor = 9999;
    int side1;
    int s2;
    for(i=0; i<sp; i++)
     for(j=i+1; j<=sp; j++)
     {
       x1 = outer[i].x + outer[j].x;
       y1 = outer[i].y + outer[j].y;
       // 这两个墙端点位于某一侧外墙 
       if(x1==0||y1==0||x1==200||y1==200)
       {
          door = 0;
          for(k=0; k<n; k++)
          {
            side1 = side[k].a*x1 + side[k].b*y1 + 2*side[k].c; //是2倍 
            if(side1>0) s2 = 1;
            else if(side1<0) s2 = -1;
            else 
            {
               door = 9999; break;
            }
            if(s2!=s1[k]) door++;
          } 
          if(minDoor>door) minDoor = door;    
       } 
     }
    printf("Number of doors = %d\n",++minDoor);
    if(N) printf("\n");
  } 
return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值