• BZOJ3199 SDOI2013 逃考 半平面交、最短路


    传送门


    如果我们对于每一个点能找到与其相邻的点(即不经过其他点监视范围能够直接到达其监视范围的点)和是否直接到达边界,就可以直接BFS求最短路求出答案。

    所以当前最重要的问题是如何找到对于每一个点相邻的点。

    如果你知道泰森多边形,你就可以发现所有点的监视范围刚好对应这些点在这个矩形里的泰森多边形。

    因为两个点监视范围的分界线一定在这两个点对应线段的中垂线上,所以将当前点到所有点的中垂线拿出来跑一遍半平面交,如果某个点与当前点的中垂线在半平面交中,那么这两个点就相邻。

    还需要知道对于某个点能否不经过其他点的监视范围到达边界,这只需要在求半平面交的时候将矩形的四边也加上就可以了。

    时间复杂度(O(TN^2logN)),可能需要轻微的常数优化。

    写计算几何的时候务必注意细节,否则可能因为把(xy)坐标打反等小错误调很久QAQ

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    //This code is written by Itst
    using namespace std;
    
    #define ld long double
    const ld eps = 1e-12;
    bool cmp(ld a , ld b){return a - eps < b && a + eps > b;}
    
    struct comp{
    	ld x , y , dir;
    	comp(ld _x = 0 , ld _y = 0) : x(_x) , y(_y){dir = atan2(y , x);}
    	comp operator +(comp a){return comp(x + a.x , y + a.y);}
    	comp operator -(comp a){return comp(x - a.x , y - a.y);}
    	comp operator *(ld a){return comp(x * a , y * a);}
    	ld operator *(comp a){return x * a.x + y * a.y;}
    	ld operator %(comp a){return x * a.y - y * a.x;}
    	bool operator <(const comp a)const{return dir < a.dir;}
    	bool operator ==(const comp a)const{return cmp(dir , a.dir);}
    }now[607];
    
    struct line{
    	comp pos , dir;
    	int ind;
    	line(comp a = comp(0,0) , comp b = comp(0,0) , int id = 0) : pos(a) , dir(b) , ind(id){}
    	bool operator <(const line a)const{return dir < a.dir || dir == a.dir && ((comp)a.pos - pos) % dir > 0;}
    }cur[607];
    
    struct Edge{
    	int end , upEd;
    }Ed[370007];
    int head[607] , que[607];
    int cntEd , N , X0 , Y0 , X1 , Y1 , hd , tl , T;
    bool mrk[607] , vis[607];
    
    inline void addEd(int a , int b){
    	Ed[++cntEd] = (Edge){b , head[a]};
    	head[a] = cntEd;
    }
    
    comp rot(comp a){
    	ld Cos = 0 , Sin = 1;
    	return comp(a.x * Cos - a.y * Sin , a.x * Sin + a.y * Cos);
    }
    
    comp intersect(line a , line b){
    	ld t = (b.dir % (a.pos - b.pos)) / (a.dir % b.dir);
    	return a.pos + a.dir * t;
    }
    
    bool chk(line a , line b , line c){
    	return (intersect(a , b) - c.pos) % c.dir > 0;
    }
    
    void create(int x){
    	int cnt = 0;
    	cur[++cnt] = line(comp(0 , 0) , comp(1 , 0));
    	cur[++cnt] = line(comp(X1 , 0) , comp(0 , 1));
    	cur[++cnt] = line(comp(X1 , Y1) , comp(-1 , 0));
    	cur[++cnt] = line(comp(0 , Y1) , comp(0 , -1));
    	for(int i = 1 ; i <= N ; ++i)
    		if(i != x)
    			cur[++cnt] = line((now[i] + now[x]) * 0.5 , rot(now[i] - now[x]) , i);
    	sort(cur + 1 , cur + cnt + 1);
    	hd = tl = que[1] = 1;
    	for(int i = 2 ; i <= cnt ; ++i){
    		if(cur[i].dir == cur[i - 1].dir) continue;
    		while(hd < tl && chk(cur[que[tl]] , cur[que[tl - 1]] , cur[i]))
    			--tl;
    		while(hd < tl && chk(cur[que[hd]] , cur[que[hd + 1]] , cur[i]))
    			++hd;
    		que[++tl] = i;
    	}
    	while(hd < tl && chk(cur[que[tl]] , cur[que[tl - 1]] , cur[que[hd]]))
    		--tl;
    	while(hd <= tl){
    		if(!cur[que[hd]].ind) mrk[x] = 1;
    		else addEd(cur[que[hd]].ind , x);
    		++hd;
    	}
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("in","r",stdin);
    	//freopen("out","w",stdout);
    #endif
    	ios::sync_with_stdio(0);
    	for(cin >> T ; T ; --T){
    		cntEd = 0;
    		memset(mrk , 0 , sizeof(mrk));
    		memset(vis , 0 , sizeof(vis));
    		memset(head , 0 , sizeof(head));
    		cin >> N >> X1 >> Y1 >> X0 >> Y0;
    		if(!N){cout << "0
    "; continue;}
    		for(int i = 1 ; i <= N ; ++i)
    			cin >> now[i].x >> now[i].y;
    		for(int i = 1 ; i <= N ; ++i)
    			create(i);
    		queue < int > q;
    		ld minDis = 1e18;
    		int minInd = 0;
    		for(int i = 1 ; i <= N ; ++i){
    			ld dis = sqrt((now[i].x - X0) * (now[i].x - X0) + (now[i].y - Y0) * (now[i].y - Y0));
    			if(dis < minDis){minDis = dis; minInd = i;}
    		}
    		vis[minInd] = 1;
    		q.push(minInd);
    		bool f = 0;
    		for(int i = 1 ; !f ; ++i){
    			for(int j = q.size() ; !f && j ; --j){
    				int t = q.front(); q.pop();
    				if(mrk[t]){f = 1; continue;}
    				for(int i = head[t] ; i ; i = Ed[i].upEd)
    					if(!vis[Ed[i].end]){
    						vis[Ed[i].end] = 1;
    						q.push(Ed[i].end);
    					}
    			}
    			if(f) cout << i << endl;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    题目1522:包含min函数的栈
    [Swift]LeetCode1157. 子数组中占绝大多数的元素 | Online Majority Element In Subarray
    [Swift]LeetCode1156. 单字符重复子串的最大长度 | Swap For Maximum Repeated Substring
    [Swift]LeetCode1153. 字符串转化 | String Transforms Into Another String
    [Swift]LeetCode1151. 最少交换次数来组合所有的 1 | Minimum Swaps to Group All 1's Together
    [Swift]LeetCode1154. 一年中的第几天 | Ordinal Number Of Date
    [Swift]LeetCode1152. 用户网站访问行为分析 | Analyze User Website Visit Pattern
    [Swift]LeetCode1150. 检查一个数是否在数组中占绝大多数 | Check If a Number Is Majority Element in a Sorted Array
    [Swift]LeetCode1146. 快照数组 | Snapshot Array
    [Swift]LeetCode1147. 段式回文 | Longest Chunked Palindrome Decomposition
  • 原文地址:https://www.cnblogs.com/Itst/p/10479442.html
Copyright © 2020-2023  润新知