[CODEVS 1244] 云中通信

描述

天空中有n朵云,在风吹之下以恒定速度v=(vx,vy) 向同一个方向持续移动,也就是说,当时间为t(t≥0)时,云上初始坐标为(x, y)的点移到坐标为( x + t*vx, y + t*vy)的位置。

为简单起见,我们假设云是多边形的(而且其顶点具有整数坐标)。多边形不一定是凸的,但是每个多边形的任意两条边不相交(允许具有公共的端点)。云和云可能会重叠。

地面上有一人造卫星控制中心,位于坐标(0,0)处,在控制中心正上方的云层之上,有一颗人造卫星。一道激光束从控制中心笔直地向上射向人造卫星,这道激光束用于与卫星进行通信。然而,当激光束的光路被云遮住时,通信就会中断。最初激光束不与任何一片云相交。在观测期间,会有若干个这样的时段,在这些时段期间激光束的光路穿过一片或几片云,使得通信中断。甚至当激光束遇到云的某个顶点时,通信也会有瞬间的中断。你需要写一个程序来计算在所有云移过之前,通信会中断多少次。

http://codevs.cn/problem/1244/


分析

这个题题意一直理解的不对, 是只要激光束被挡住就算通信终端还是发射激光的点被挡住才算通信终端? 看样例是后者, 但光沿直线传播的道理是不能被更改的… …

好吧, 实在不会写, 把标程注释翻译了一遍 (原文是英文注释), 加了些自己的理解, 也不知道对不对.

感觉太高端了, 手写分数类、手写62位大整数乘法… 晕!


代码

1367ms 19MB



跟原程序比把随机调换交点顺序的代码删除了, 搞不懂怎么回事, 而且那段代码风格都和其他地方不一样. 闹哪样?

/*************************************************************************}
{*                                                                       *}
{*                                  CEOI 2004                            *}
{*                                                                       *}
{*   Sample solution:     Clouds                                         *}
{*   File:                CLO.CPP                                        *}
{*   Author:              PIOTR STANCZYK                                 *}
 *************************************************************************/
#include <cstdio>
#include <algorithm>
#include <vector>
#define MAX_CLOUDS 1000
#define CLOUD_SIZE 1000
#define LOCAL

typedef long long int lli;
typedef unsigned long long int ulli;
const ulli low_part  = 2147483647;                /* 2^31 - 1 */ // 31 个 1
const ulli high_part = low_part * (low_part + 2); /* 2^62 - 1 */ // 62 个 1
using namespace std;

struct point {
    int x,y;
};

struct superlong {
    ulli high, low;
};

struct crossing {  /* Intersection point             */ // 云和激光的交点
    lli posh, posl;  /* Relative position of the point */ // 在激光上的位置 (比例)
    short int cloud; /* Owner of the point             */ // 所在的云
    char type;       /* Type of intersection           */ // 交点类型
};

int vel_x, vel_y, clouds; /* Velocity vector and the number of clouds */ // 移动速度正交分解
vector<crossing> cr;      /* Vector of intersection points            */ // 存激光和云的交点 

inline superlong multiply(ulli v1, ulli v2)
/* Multiplies two unsigned long long ints and returns the result as superlong. *
 * This function assumes that multiplied values are at most 62-bits long       */ // 两个无符号长整型 v1,v2 相乘的结果
{
    superlong val;
    ulli x = (v1 & low_part) * (v2 >> 31) + (v1 >> 31) * (v2 & low_part);
    // x = v1 的后31位乘上 v2 右移31的结果 + v1 的后31位乘上 v2 右移31的结果 = ??
    val.low = (v1 & low_part) * (v2 & low_part);
    val.high = (v1 >> 31) * (v2 >> 31);
    val.low  += (x & low_part) << 31;
    val.high += (x >> 31) + (val.low >> 62);
    val.low  = val.low & high_part;
    return val;
}

inline int compare(const crossing& a, const crossing& b)
/* Compares a position of two given crossing points */
// 先考虑高位再考虑低位判断大小
{
    // a : a.posh / a.posl ( > 0 )
    // b : b.posh / b.posl ( > 0 )
    // a - b : a.posh*b.posl - a.posl*b.posh / (a.posl*b.posl)
    // 在正负符号上 = a.posh*b.posl - a.posl*b.posh
    superlong a1 = multiply(a.posh, b.posl);
    superlong b1 = multiply(a.posl, b.posh);
    if (a1.high == b1.high) {
        if (a1.low == b1.low) return 0; // a = b
        if (a1.low < b1.low) return -1; // a < b
        return 1; // a > b
    }
    if (a1.high < b1.high) return -1;
    return 1;
}

inline bool cmp(const crossing& a, const crossing& b)
{
    return (compare(a, b) == -1); // return a < b (比较a, b到激光发射点 (point [0,0]) 的相对距离大小)
}

int side(const point& a)
/* Determines the location of a given point against velocity vector */ // 计算给定顶点和速度向量的相对位置
{
    lli x = (lli)vel_x * (lli)a.y - (lli)vel_y * (lli)a.x; // 向量 (vel_x, vel_y) 与 向量 (a.x, a.y) 的 叉积
    if (x == 0) return 0; // 两个向量重合 即速度向量过该点
    if (x > 0) return 1;  // 点在速度向量上方
    return -1;            // 点在速度向量下方
}

void Add_intersection(const point& a, const point& b, short int cloud, char type)
/* Examines an intersection point between velocity vector and (a,b) segment */
// 检查 速度向量 和 线段ab 的交点情况
{
    crossing c;
    /* The relative distance of the crossing point from the laser beam (point [0,0]) *
     * is defined as c.posh/c.posl. In order to keep arithmetic precision we have    *
     * to represent this value as a fraction                                         */
    // 交点和激光发射点 (point [0,0]) 的相对距离用 c.posh/c.posl 表示, 采用手写分数类的方式, 来避免精度误差
    c.posh = lli (b.y) * lli (a.x) - lli (b.x) * lli (a.y);
    c.posl = lli (vel_y) * lli (a.x - b.x) - lli (vel_x) * lli (a.y - b.y);
    if (c.posh < 0 && c.posl < 0) { // 分子分母负负得正
        c.posh = -c.posh;
        c.posl = -c.posl;
    }
    /* Examined intersection is not important for as */
    // 距离为负, 交点在激光的反向延长线上, 舍掉答案
    else if (c.posh < 0 || c.posl < 0) return; 

    c.cloud = cloud;
    c.type = type;
    cr.push_back(c);
}

void Read_Data()
/* Reads data and finds all intersection points */ // 读入数据, 找到所有速度向量与云的交点
{
    int size;
    point cloud[CLOUD_SIZE]; // 保存云上的顶点
    scanf("%d %d %d", &clouds, &vel_x, &vel_y);

    // 运用爱因斯坦狭义相对论的原理对速度进行等效的处理, 相当于云不动, 坐标中心反方向运动
    vel_x = -vel_x;
    vel_y = -vel_y;

    for(int x = 0; x < clouds; ++x) { // 一共 clouds 朵云
        scanf("%d", &size);
        for(int y = 0; y < size; ++y) {
            scanf("%d %d", &cloud[y].x, &cloud[y].y);
        }
        int pos = 0, f_side, l_side;

        /* Finds a vertex not located above velocity vector */
        // 找到一个不位于速度向量上的顶点 速度向量不过该点
        while ( (f_side = side(cloud[pos])) == 0) ++pos; 

        int y = 1;
        while (y <= size) {
            l_side = f_side; // l_side 一定不能等于 0
            f_side = side(cloud[(pos + y) % size]); // 与当前顶点相邻的下一个顶点与速度向量的相对位置
            switch (l_side * f_side) {

                case 1 :
                /* Vertices are located on the same side -> no intersection */
                // 两顶点位于速度向量的同一侧, 连线和速度向量无交点
                ++y;
                break;

                case -1 :
                /* Vertices are located on a different sides -> intersection found */
                // 两顶点位于速度向量的不同侧, 连线和速度向量有交点
                Add_intersection(cloud[(pos + y - 1) % size], cloud[(pos + y) % size], x, 0);
                ++y;
                break;

                case 0 :
                /* Vertex is located directly above velocity vector -> further verification */
                // (pos + y) 位于速度向量上
                int beg = pos + y;
                while ( (f_side = side(cloud[(pos + y) % size])) == 0) ++y;
                if (pos + y != beg + 1) {
                    // 有很多交点, 但只记录下两个
                    Add_intersection(cloud[(pos + y) % size], cloud[(pos + y - 1) % size], x, (l_side == f_side) ? 1 : 2);
                    Add_intersection(cloud[(beg - 1) % size], cloud[beg % size], x, 1);
                } else {
                    // 只有一个交点 (pos + y), 如果没有穿过激光, type = 3, 否则 type = 0
                    Add_intersection(cloud[(pos + y - 1) % size], cloud[(pos + y) % size], x, (l_side == f_side) ? 3 : 0);
                }
                break;
            }
        }
    }
}

int Count_Result()
/* Searches the sorted list of intersection points and calculates the result */
// 扫描排好序的交点列表, 统计答案
{
    bool inside[MAX_CLOUDS];  /* is a cloud directly above the laser beam */            // 激光当前是否在该云里面
    bool on_edge[MAX_CLOUDS]; /* is an edge of a cloud directly above the laser beam */ // 激光当前是否在该云边缘
    int am_edges = 0, am_inside = 0, result = 0;
    crossing location;
    location.posh = 0; /* Sets the actual location to the    */ // 从初始化的距离为 0 开始扫描
    location.posl = 1; /* initial position of the laser beam */ // 分母不是 0 即可 

    for(int x = 0; x < clouds; ++x)
    inside[x] = on_edge[x] = false;

    for(__typeof (cr.begin()) it = cr.begin(); it != cr.end(); ++it) {
        // 以下三项判断分别对应着: 当前的激光不在云中, 当前的激光不在云的边缘, 当前点与上个点不重合
        if (am_inside == 0 && am_edges == 0 && compare(location,*it) != 0)
        ++result;

        location = *it;

        if (location.type == 1 || location.type == 2)
        /* Intersection changes the state of an edge */
        // 交点情况改变边的状态 激光从该云的边缘上移开 或 激光移动到了该云的边缘上
        (on_edge[location.cloud] = !on_edge[location.cloud]) ? ++am_edges : --am_edges;

        if (location.type == 0 || location.type == 2)
        /* Intersection changes the state of a cloud */
        // 交点情况改变云的状态 激光从该云中移出 或 激光进入该云
        (inside[location.cloud] = !inside[location.cloud]) ? ++am_inside : --am_inside;
    }
    return result;
}

int main()
{
    Read_Data();

    // 把交点按照距离激光发射点 (point [0,0]) 的相对距离从近到远排序
    sort(cr.begin(), cr.end(), cmp);

    printf("%d\n", Count_Result());
    return 0;
}
时间: 2024-10-19 02:18:25

[CODEVS 1244] 云中通信的相关文章

总结-计算几何

计算几何 做的题目很少, 而且模版也不熟. 所以还有这几天的时间, 把几个经典的算法弄熟弄懂, 模版能打出来就行了吧. 1. 凸包 2. 旋转卡壳 3. 半平面交 题目: 1. [codevs 1249] 多边形的面积 求多边形面积, 要理解叉积的意义. 2. [codevs 1298] 凸包周长 [codevs 3201] 奶牛代理商 XI 凸包周长 3. [codevs 1302] 小矮人(2002年CEOI中欧信息学奥赛) 旋转卡壳求对踵点 4. [codevs 3273] 两圆的交 这个

Docker六大优势,云中部署模式、以及视频demo

随着Docker技术的不断成熟,越来越多的企业开始考虑使用Docker.Docker有很多的优势,如持续集成.版本控制.可移植性.隔离性.安全性和高性能. 另外一方面如何在企业云中实施docker,是直接使用docker(Cloud by Docker)还是将docker运行在vm中进行管理(Docker in Cloud)? 本文将总结优势,分析部署模式,以及最后通过2个视频demo来了解下云中运行docker的模式情况 1.六大优势 1.1 持续部署与测试 Docker在开发与运维的世界中具

跨平台视频通信项目-OpenTok

1 理论知识 1.1 OpenTok平台简介 即时视频通信日益成为主流服务,通过WebRTC,开发者可以轻松地将即时视频通信功能加入到应用中.视频聊天创业公司TokBox推出OpenTok,可实现浏览器与iOS设备间跨平台视频聊天. OpenTok平台可以轻松实现以下功能: - 高质量的互动视频 - 消息传递 - 屏幕分享 1.2 基本概念 1.2.1 客户端SDK 一组可用于Web(JavaScript),IOS和Android的代码库,用于设置客户端(处理大多数OpenTok的功能能),功能

ORA-03113 通信通道的文件结尾(ORA-19804 ORA-16038-归档空间满的处理方法)

1.数据库启动报错SQL> startupORACLE 例程已经启动. Total System Global Area 1887350784 bytesFixed Size 2176848 bytesVariable Size 1325402288 bytesDatabase Buffers 553648128 bytesRedo Buffers 6123520 bytes数据库装载完毕.ORA-03113: 通信通道的文件结尾进程 ID: 1244会话 ID: 96 序列号: 3 2.查看告

codevs 5960 信使

codevs 5960 信使 题目描述 Description 战争时期,前线有n个哨所,每个哨所可能会与其他若干个哨所之间有通信联系.信使负责在哨所之间传递信息,当然,这是要花费一定时间的(以天为单位).指挥部设在第一个哨所.当指挥部下达一个命令后,指挥部就派出若干个信使向与指挥部相连的哨所送信.当一个哨所接到信后,这个哨所内的信使们也以同样的方式向其他哨所送信.直至所有n个哨所全部接到命令后,送信才算成功.因为准备充足,每个哨所内都安排了足够的信使(如果一个哨所与其他k个哨所有通信联系的话,

vue基础----组件通信($parent,$children)

1.按照dom的父子级关系,在子组件中可以通过$parent 直接调用父组件的方法,也可得到父组件的属性. 2.在父组件中通过$childrens可以得到一个子组件数组,能够在父组件中调用子组件的方法和得到属性. 3.特别注意一下_uid标识每一个组件. 下面是一个下拉菜单举例 1 <body> 2 <div id="app"> 3 <collapse> 4 <collapse-item title="大学同学">大学

Java网络编程之tcp的socket通信

1.客户端MyClient.java 1 import java.io.*; 2 import java.net.*; 3 4 public class MyClient 5 { 6 public static void main(String[] args)throws Exception 7 { 8 Socket s = new Socket("192.168.1.1" , 30000); 9 // 客户端启动ClientThread线程不断读取来自服务器的数据 10 new Th

Android实现组件之间同步的回调通信

Android开发中,有时会遇到组件之间相互通信回调的问题.一般都是通过Android提供的ResultReceiver来实现(ResultReceiver的使用方法很简单,这里就不多提了). 但之前在工作中,遇到了一个组件间回调的问题,ResultReceiver无法满足需求.简单描述一下问题:service中打开了一个activity,activity需要将一个变量值回调给service,而且这个回调必须是同步的.也就是说activity在确认service接收到了这个变量值后,才能继续向下

Java多线程编程核心技术读书笔记(3)-线程通信

线程是操作系统中独立的个体,但是这些个体如果无法经过特殊的处理就不能成为一个整体.线程间通信可以实现线程间的信息互换.相互唤起等功能,是系统的交互性更加强大,大大提高CPU的利用率,同时还能让开发者对各个线程任务有清晰的把控和监督,最常用的线程通信方法就是--等待/通知机制. 一.等待/通知机制 1.wait() / notify() 等待/通知机制在生活中比比皆是,例如:厨师/服务员的菜品传递台.生产者/消费者模式,JDK中通过Object里面的两个方法 wait() / notify() 来