SGU 110. Dungeon 计算几何 难度:3

110. Dungeon

time limit per test: 0.25 sec. 
memory limit per test: 4096 KB

 

The mission of space explorers found on planet M the vast dungeon. One of the dungeon halls is fill with the bright spheres. The explorers find out that the light rays reflect from the surface of the spheres according the ordinary law (the incidence angle is equal to the reflectance angle, the incidence ray, the reflected ray and the perpendicular to the sphere surface lay in the one plane). The ancient legend says that if the light ray will reflect from the spheres in the proper order, than the door to the room with very precious ancient knowledge will open. You are not to guess the right sequence; your task is much simpler. You are given the positions and the radii of the spheres, the place where the laser shot was made and the direction of light propagation. And you must find out the sequence in which the light will be reflected from the spheres.

 

Input

The first line of input contains the single integer n (1≤n≤50) - the amount of the spheres. The next n lines contain the coordinates and the radii of the spheres xi, yi, zi, ri (the integer numbers less or equal to 10000 by absolute value). The last line contains 6 real numbers - the coordinates of two points. The first one gives the coordinates of the place of laser shot, and the second gives the direction in which it was made (the second point is the point on the ray). The starting point of the ray lies strictly outside of any sphere.

 

Output

Your program must output the sequence of sphere numbers (spheres are numbers from 1 as they was given in input), from which the light ray was reflected. If the ray will reflect more the 10 times, than you must output first 10, then a space and the word 'etc.' (without quotes). Notice: if the light ray goes at a tangent to the sphere you must assume that the ray was reflected by the sphere.

 

Sample Input 1

1 
0 0 2 1 
0 0 0 0 0 1

Sample Output 1

1

Sample Input 2

2 
0 0 2 1 
0 0 -2 1 
0 0 0 0 0 100

Sample Output 2

1 2 1 2 1 2 1 2 1 2 etc.

感想:计算几何远观的时候最难
思路:
1 判断射线反射交哪个球 如果使用点斜式会在0处出问题,题解使用了起点到球的距离相对射线反向的倍数,注意当这个倍数为0的时候,只要不是从这个球反射出去的也成立(也就是开始的时候光源就在这个球表面)
2 求反射后的光线向量,做一个以入射光线为平行边的一边,法线(圆心-入射点方向)为对角线做一个菱形,明显反射光线就是另外一边..的反向(!),所以反射光线就是入射向量-入射光线在法线上的投影*2,在这个地方弄成法线在入射光线WA一次
投影为单位法线*(入射和法线的点积)
最后注意一下,先判断有没有第11次反射再输出"etc."
#include<cstdio>
#include <cstring>
#include <cmath>
using namespace std;
class  pnt{
    public :
        double x,y,z;
        pnt():x(0),y(0),z(0){}
        pnt(double tx,double ty,double tz):x(tx),y(ty),z(tz){}
        pnt operator -(pnt besub){
            pnt ans;
            ans.x=x-besub.x;
            ans.y=y-besub.y;
            ans.z=z-besub.z;
            return ans;
        }
        pnt operator +(pnt beadd){
            pnt ans;
            ans.x=x+beadd.x;
            ans.y=y+beadd.y;
            ans.z=z+beadd.z;
            return ans;
        }
        pnt operator*(double bemul){
            pnt ans;
            ans.x=x*bemul;
            ans.y=y*bemul;
            ans.z=z*bemul;
            return ans;
        }
        pnt operator/(double bediv){
            pnt ans;
            ans.x=x/bediv;
            ans.y=y/bediv;
            ans.z=z/bediv;
            return ans;
        }
        double  dot(pnt bepnt){
            return x*bepnt.x+y*bepnt.y+z*bepnt.z;
        }
        double caldis(pnt other){
            return sqrt((x-other.x)*(x-other.x)+(y-other.y)*(y-other.y)+(z-other.z)*(z-other.z));
        }
        double len(){
            return sqrt(x*x+y*y+z*z);
        }
};

pnt ball[51],nowref,dir,start,normal;
double ballr[51],mindis,nowdis;
int n,nowball,nxtball;
const double inf=1e18;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf%lf%lf",&ball[i].x,&ball[i].y,&ball[i].z,ballr+i);
    }
    scanf("%lf%lf%lf%lf%lf%lf",&start.x,&start.y,&start.z,&dir.x,&dir.y,&dir.z);
    dir=dir-start;
    dir=dir/dir.len();
    nowball=0;
    for(int time=0;time<11;time++){
        nxtball=0;
        mindis=inf;
        for(int i=1;i<=n;i++){//开始使用了点法式,不行...换成比例简洁不出错
            if(i==nowball)continue;
            double a=dir.x*dir.x+dir.y*dir.y+dir.z*dir.z;
            double b=2*(dir.x*(start.x-ball[i].x)+dir.y*(start.y-ball[i].y)+dir.z*(start.z-ball[i].z));
            double c=(start.x-ball[i].x)*(start.x-ball[i].x)+(start.y-ball[i].y)*(start.y-ball[i].y)+(start.z-ball[i].z)*(start.z-ball[i].z)-ballr[i]*ballr[i];
            double delta=b*b-4*a*c;
            if(delta<0)continue;

            nowdis=(-b+sqrt(delta))/2/a;
            if(nowdis>=0&&nowdis<mindis){//ATTENTION
                    mindis=nowdis;
                    nxtball=i;
                    nowref=start+dir*(nowdis);
            }
            nowdis=(-b-sqrt(delta))/2/a;
            if(nowdis>=0&&nowdis<mindis){//ATTENTION
                    mindis=nowdis;
                    nxtball=i;
                    nowref=start+dir*(nowdis);
            }
        }

        if(nxtball==0){break;}
        if(time)putchar(' ');
        if(time<10)printf("%d",nxtball);
        else {puts("etc.");break;}

        normal=ball[nxtball]-nowref;
        normal=normal/normal.len();
        dir=dir-normal*(normal.dot(dir)*2.00);
        start=nowref;
        nowball=nxtball;
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/xuesu/p/4007326.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
import json import requests import sqlite3 import time import threading channel_id = '1114886706903138365' # 连接到SQLite数据库 # 创建本地存储对象 local = threading.local() def get_connection(): # 检查本地存储对象中是否已经创建了连接对象 if not hasattr(local, 'conn'): # 如果没有,则创建连接对象 local.conn =sqlite3.connect('D:/SQLDATA/aaa.db') #连接数据库 return local.conn TOKEN = 'MTExNDA3NDUzMDE1NjEzMDMzNQ.GFKaeX.PVshsn-1qzFCqVBK6RU865CvKld_SUl1f8mP6g' headers={"Content-Type": "application/x-www-form-urlencoded", # 'Authorization':TOKEN, 'authorization': 'OTQwNTc3NzUyODEyMjM2ODAw.GILEVR.F_Ehv2MQ_lVUNiI3Ip7sGu0TgDKNyOyswcPnv8' } req = requests.get( 'https://discordapp.com/api/v9/channels/1070425809321480272/messages?limit=50', headers=headers) resss = req.content.decode('utf-8') data = json.loads(resss) def getcontent(): # 获取连接对象 conn = get_connection() # 创建游标对象 c = conn.cursor() for article in data: # 内容 id=article['id'] content = article['content'] # 频道ID channel_id = article['content'] # author author_id = article['author']['id'] author_name = article['author']['username'] timestamp = article['timestamp'] c.execute( "INSERT OR IGNORE INTO getData (Id,content,channel_id,author_id,author_name,timestamp,nopush) VALUES(:Id,:content,:channel_id,:author_id,:author_name,:timestamp,:nopush)", { "Id": id, "content": content, "channel_id": channel_id, "author_id": author_id, "author_name": author_name, "timestamp": timestamp, "nopush":'1' }, ) # 提交当前事务,保存数据 conn.commit() c.close() # conn.close() print(content) def run_thread(): while True: # 暂停 0.5 秒钟 time.sleep(0.5) # 创建一个线程,执行 do_something 函数 threading.Thread(target=getcontent).start() if __name__ == '__main__': run_thread() 错误在哪
06-07

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值