[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 LOCALtypedef 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.poshsuperlong 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 = bif (a1.low < b1.low) return -1; // a < breturn 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; }總結
以上是生活随笔為你收集整理的[CODEVS 1244] 云中通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [CODEVS 3147] 矩阵乘法 2
- 下一篇: [BZOJ 2243] 染色