codeforces计算几何刷题记录【每日一题】

codeforces里面的计算几何我平时都有刷,但是总是懒懒散散的,直到昨天的一场训练赛,作为计算几何选手的我被一道计算几何题卡了几乎整场,虽然这题是防ak题,但赛后补出来发现并不是很难,主要原因还是我计算几何太弱了。于是乎,蒟蒻我下定决心从今天开始,每天至少刷一道计算几何(其他时间可能要补补cf或者学学其他算法的,所以就不强制整天练计几了)。

以此记录!!codeforces 的problemset,tag选择计算几何,按照难度排序,从第一篇最后一题往上刷。加油!!!。

 (后补:发现cf上面有些计几题其实考察的不是计几,所以就挑一些比较计几的计几题来做了,然后也不局限于cf了,反正每天坚持一道不水的计几就好了)

https://codeforces.com/problemset/page/1?tags=geometry&order=BY_RATING_DESC

开始!!

2020.4.6: 第一题:Delivering Carcinogen

二分然后套个圆的板子就ok了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define eps 1e-6
 4 const double pi = acos(-1.0);
 5 struct Point{
 6     double x,y,v;
 7     Point rotate(double deta){
 8         return (Point){ x * cos(deta) - y*sin(deta),x*sin(deta) + y * cos(deta)};
 9     }
10 }a,b;
11 double dist(Point a,Point b){
12     return sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y-b.y));
13 }
14 double cross(Point a,Point b,Point c){
15     return (b.x - a.x) * (c.y-a.y) - (c.x - a.x) * (b.y - a.y);
16 }
17 struct Circle{
18     Point o;
19     double r;
20     //圆心出发的射线的交点
21     Point getPoint(double deta){
22         return (Point){o.x + cos(deta)*r , o.y + sin(deta)*r};
23     }
24     //两个圆上的点的最短圆弧
25     double getPointDis(Point a,Point b){
26         double deta = fabs( atan2(a.y - o.y,a.x - o.x) - atan2(b.y - o.y,b.x - o.x));
27         deta = min(deta,2*pi - deta);
28         return deta * r;
29     }
30     //ab线段和圆是否相交
31     bool is_insert(Point a,Point b){
32         double ab = dist(a,b);
33         double d = fabs(cross(o,a,b)) / ab;
34         if( d > r - eps) return 0;
35         double oa = dist(a,o) , ob = dist(o,b);
36         double ta = (oa*oa + ab*ab - ob*ob)/2*oa*ab;
37         double tb = (ob*ob + ab*ab - oa*oa)/2*oa*ab;
38         if(ta < -eps || tb < -eps) return 0;
39         return 1;
40     }
41 }cir;
42 //求切点
43 void getTangentPoints(Point p,Circle C , Point& r1,Point& r2){
44     double d = dist(p,C.o);
45     double base = atan2(p.y - C.o.y,p.x - C.o.x);
46     double deta = acos( C.r/d );
47     r1 = C.getPoint(base - deta);
48     r2 = C.getPoint(base + deta);
49 }
50 int sgn(double x){
51     if( fabs(x) < eps) return 0;
52     if( x > 0) return 1;
53     return -1;
54 }
55 bool judge(double t){
56     double R = sqrt( a.x * a.x + a.y * a.y);
57     double w = a.v / R ;
58     Point c = a.rotate(w * t);
59     if(cir.is_insert(b,c) == 0 ) return dist(b,c) < t*b.v + eps;
60     Point cutb1 , cutb2;
61     getTangentPoints(b,cir,cutb1,cutb2);
62     Point cutc1 , cutc2;
63     getTangentPoints(c,cir,cutc1,cutc2);
64     double tem1 = dist(b,cutb2) + dist(c,cutc1) + cir.getPointDis(cutb2,cutc1); 
65     double tem2 = dist(b,cutb1) + dist(c,cutc2) + cir.getPointDis(cutb1,cutc2);
66     return min( tem1,tem2 ) < t*b.v + eps;
67 }
68 int main(){
69     scanf("%lf %lf %lf",&a.x,&a.y,&a.v);
70     scanf("%lf %lf %lf %lf",&b.x,&b.y,&b.v,&cir.r);
71     cir.o = (Point){0,0};
72     double le = 0 , ri = 100000000;
73     double res;
74     while( ri - le > eps){
75         double m = (ri+le)/2;
76         if(judge(m)){
77             res = m;
78             ri = m;
79         }
80         else le = m;
81     }
82     printf("%.9f",res);
83     return 0;
84 }
View Code

 

2020.4.7:第二题:Kingdom Trip (K题)

这题我们把两两是否有边建立出来,然后直接来个n方dp就好了。问题是怎么建边。

我们判断线段ab和圆是否有交,其实是判断圆心到线段距离<R,并且两个非圆心夹角是锐角。然后其实我们还可以过a做圆o的切线,判断b是否在o切线夹角里面,那么假如ab在圆同一侧呢?没关系,我们反过来再做一次判断就好了。具体判断就是,枚举起点i,然后依次往后判断j,然后判断完j之后,把 j 的切线夹角和原来的求个交就好了。

然后其实判断夹角交有一个很好的做法就是:我们把第一个角度ph0设为基准,然后夹角范围我们用相对于ph0的deta来表示,左夹角为ph0 + l , 右夹角为 ph0 + r,那么我们每一次要交的是夹角角度是

[ phj - deta , phj + deta] ,那么我们只需要判断phj 和 ph0 之间的绝对夹角 theta, 然后   l = max(l,theta-deta);     r = min(r,theta+deta); 即可。

这样比那种直接把左右角度表示出来好很多,因为左右角度表示出来很容易出现 l >r ,烦得要死。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define eps 1e-7
 4 const int N = 2e3+9;
 5 #define inf 1e8
 6 const double pi = acos(-1.0);
 7 struct Point{
 8     double x,y;
 9 }p[N];
10 int dp[N],G[N][N];
11 double cross(Point a,Point b,Point c){
12     return (b.x-a.x)*(c.y-a.x) - (c.x-a.x)*(b.y-a.y);
13 }
14 double dist(Point a,Point b){
15     return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
16 }
17 int n; 
18 double d;
19 double solve(double x){
20     if(x>pi+eps) return x - 2*pi;
21     if(x<-pi - eps) return x + 2*pi;
22     return x;
23 }
24 void init(bool fg){
25     for(int i = 1;i<n;++i){
26         double ph0 = inf,l,r;
27         for(int j = i+1;j<=n;++j){
28             double dd = dist(p[i],p[j]);
29             bool ok = 1;
30             double phj = atan2(p[j].y-p[i].y,p[j].x-p[i].x);
31             double theta = solve(phj-ph0);
32             if(ph0 != inf){
33                 if(theta < l - eps || theta > r + eps) ok = 0;
34             }
35             if(ok){
36                 if(fg) G[i][j] = 1;
37                 else G[n+1-i][n+1-j] = 1;
38             }
39             if(dd < d - eps) continue;
40             double deta = asin(d/dd);
41             if(ph0 == inf){
42                 ph0 = phj;
43                 l = -deta;
44                 r = deta;
45             }
46             else{
47                 l = max(l,theta-deta);
48                 r = min(r,theta+deta);
49             }
50         }
51     }
52 }
53 void work(){
54     memset(dp,127,sizeof(dp));
55     dp[n] = 1;
56     for(int i = n-1;i>=1;--i){
57         for(int j = i+1;j<=n;++j){
58             if(G[i][j] && G[j][i]) dp[i] = min(dp[i],dp[j] + 1);
59         }
60     }
61     printf("%d",dp[1]);
62 }
63 int main(){
64     freopen("kingdom.in", "r", stdin);
65     freopen("kingdom.out", "w", stdout);
66     scanf("%d %lf",&n,&d);
67     for(int i = 1;i<=n;++i) scanf("%lf %lf",&p[i].x,&p[i].y);
68     init(0);
69     reverse(p+1,p+1+n);
70     init(1);
71     // for(int i = 1;i<=n;++i){
72     //     for(int j = 1;j<=n;++j){
73     //         cerr<<i<<" "<<j<<" "<<G[i][j]<<endl;
74     //     }
75     // }
76     work();
77     return 0;
78 }
View Code

 

2020.4.8 第三题 : Split Game

第一象限给你一个简单多边形,问你从原点连一条射线,能分成多边形最多多少份

很明显就是扫描线啦,极角排序然后扫描线,按照每一个点与左右两边的点的位置关系来判断是+1还是-1,需要注意的是,我们平时的扫描线是把+1的放前,-1放后,贪心。但是这里我们不能贪心,一定得把这条线答案统计完再更新答案。还有就是,有一些点是扫描线到这点就更新,有一些点是到这个点之后才更新,所以给他一个fr标记,标记它的前后。

也不是很难。。。。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1e5+9;
 4 typedef long long ll;
 5 struct Point{
 6     ll x,y;
 7     int id,ty,fr;
 8     ll len(){return x*x+y*y;}
 9 }p[N],tem[N],p0;
10 ll cross(Point a,Point b,Point c){
11     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
12 }
13 bool cmp(Point a,Point b){
14     if(cross(p0,a,b) == 0 ) return a.fr > b.fr;
15     return cross(p0,a,b) > 0;
16 }
17 int n; 
18 void init(){
19     int nn = 0;
20     p[nn++] = tem[0];
21     for(int i = 1;i<n;++i){
22         while( nn >= 2 && cross(p[nn-2],p[nn-1],tem[i]) == 0 ){
23             --nn;
24         }
25         p[nn++] = tem[i]; 
26     }
27     n = nn;
28 }
29 int main(){
30     scanf("%d",&n);
31     p0.x = p0.y = 0;
32     for(int i = 0;i<n;++i){
33         scanf("%lld %lld",&tem[i].x,&tem[i].y);
34     }
35     init();
36     for(int i = 0;i<n;++i) p[i].id = i;
37     for(int i = 0;i<n;++i){
38         Point l = p[ (i - 1 + n ) % n];
39         Point r = p[ (i + 1 ) % n];
40         ll cl = cross(p0,p[i],l) , cr = cross(p0,p[i],r);
41         if( cl > 0 && cr > 0 ){
42             p[i].ty = 1;
43             if(cross(p[i],l,r) > 0 ) p[i].fr = 1;
44             else p[i].fr = -1;
45         }
46         else if( cl < 0 && cr < 0 ){
47             p[i].ty = -1;
48             if(cross(p[i],l,r) > 0 ) p[i].fr = -1;
49             else p[i].fr = 1;
50         }
51         else if(cl == 0){
52             Point llp = p[ (i - 2 + n ) % n];
53             ll cll = cross(p0,p[i],llp);
54             if(cll > 0 && cr > 0) p[i].ty = 1;
55             else if( cll < 0 && cr < 0 ) p[i].ty = -1;
56             if(l.len() < p[i].len()) p[i].fr = -1;
57             else p[i].fr = 1;
58         }
59     }
60     ll ans = 1, now = 1;
61     sort(p,p+n,cmp);
62     for(int i = 0;i<n;++i){
63         // cerr<<p[i].x<<" "<<p[i].y<<" "<<p[i].ty<<" "<<p[i].fr<<endl;
64         if( i > 0 && cross(p0,p[i],p[i-1]) == 0 && p[i].fr == p[i-1].fr ) now += p[i].ty;
65         else{
66             ans = max(now,ans);
67             now += p[i].ty;
68         }
69     }
70     ans = max(ans,now);
71     printf("%d",ans);
72     return 0;
73 }
View Code

 

2020.4.10 第四题:Alice and Bomb

题意:二维平面有一个点是光源,有n个简单多边形,问从原点走到阴影处最短距离

昨天咕咕咕了一天,今天补回来。这题其实就是一个寻路问题,寻路问题就是扣关键点,然后对关键点连边,最后跑最短路。这题最终答案肯定是走某一条垂线,所以直接跑最短路,连边就是各个顶点以及垂足。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-6
  4 const double inf = 1e30;
  5 const double pi = acos(-1.0);
  6 struct Point{
  7     double x,y;
  8     double dis;
  9     bool ok;
 10     int id;
 11     Point(){}
 12     Point(double xx,double yy){
 13         x = xx; y = yy;
 14     }
 15     bool operator < (const Point& b)const{
 16         return dis > b.dis;
 17     }
 18     Point operator + (const Point& b)const{
 19         return (Point){x+b.x,y+b.y};
 20     }
 21     Point operator * (const double& b)const{
 22         return (Point){b*x,b*y};
 23     }
 24 }p0,A;
 25 struct Line{
 26     Point s,e;
 27     double a,b,c;
 28     Line(Point p1,Point p2){
 29         s = p1, e = p2;
 30         a = p2.y - p1.y;
 31         b = p1.x - p2.x;
 32         c = p2.x * p1.y - p1.x * p2.y;
 33     }
 34 };
 35 int n; 
 36 const int N = 1000+9;
 37 vector<Point> pol[N];
 38 double dis[N][N];
 39 double ans[N];
 40 bool can[N];
 41 int cnt;
 42 int sgn(double x){
 43     if(fabs(x) < eps ) return 0;
 44     if(x>0) return 1;
 45     return -1;
 46 }
 47 double dist(Point a,Point b){
 48     return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
 49 }
 50 double cross(Point a,Point b,Point c){
 51     return (b.x - a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
 52 }
 53 double dot(Point a,Point b,Point c){
 54     return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y);
 55 }
 56 Point footOfLine(Line l,Point p){
 57     double t = (l.a * p.x + l.b*p.y + l.c) / (l.a * l.a + l.b * l.b);
 58     return p + Point(l.a,l.b) * t;
 59 }
 60 bool insert(Line l1,Line l2){
 61     return 
 62         max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&
 63         max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&
 64         max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&
 65         max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&
 66         sgn( cross(l1.s,l2.s,l1.e) ) * sgn( cross(l1.s,l2.e,l1.e)) < 0 &&
 67         sgn( cross(l2.s,l1.s,l2.e) ) * sgn( cross(l2.s,l1.e,l2.e)) < 0;
 68 }
 69 bool access(Point a,Point b){
 70     Line l1 = Line(a,b);
 71     for(int i = 1;i<=n;++i){
 72         for(int k = 0;k<pol[i].size()-1;++k){
 73             Line l2 = Line(pol[i][k],pol[i][k+1]);
 74             // cerr<<l2.s.x<<" "<<l2.s.y<<" "<<l2.e.x<<" "<<l2.e.y<<endl;
 75             if( insert(l1,l2) ) return 0;
 76             // cerr<<"hh"<<endl;
 77         }
 78     }
 79     return 1;
 80 }
 81 void solve(){
 82     for(int i = 1;i<=cnt;++i){
 83         for(int j = i+1;j<=cnt;++j){
 84             dis[i][j] = dis[j][i] = inf;
 85         }
 86     }
 87     for(int i = 1;i<=n;++i){
 88         for(int j = i+1;j<=n;++j){
 89             for(int a = 0;a<pol[i].size()-1;++a){
 90                 for(int b = 0;b<pol[j].size()-1;++b){
 91                     if(access(pol[i][a],pol[j][b])){
 92                         dis[pol[i][a].id][pol[j][b].id] = dis[pol[j][b].id][pol[i][a].id] = dist(pol[i][a],pol[j][b]);
 93                     }
 94                     dis[pol[i][a].id][pol[j][b].id] = dis[pol[j][b].id][pol[i][a].id] = inf;
 95                 }
 96             }
 97         }
 98     }
 99     for(int i = 1;i<=n;++i){
100         for(int j = 0;j<pol[i].size()-1;++j){
101             dis[pol[i][j].id][pol[i][j+1].id] = dis[pol[i][j+1].id][pol[i][j].id] = dist(pol[i][j],pol[i][j+1]);
102         }
103     }
104     for(int i = 1;i<=n;++i){
105         for(int j = 0;j<pol[i].size() - 1;++j){
106             if(cross(p0,pol[i][j],pol[i][j+1]) > eps){
107                 can[pol[i][j].id] = can[pol[i][j+1].id] = 1;
108                 // cerr<<"can"<<endl;
109             }
110         }
111     }
112     priority_queue<Point> q;
113     A.dis = 0;
114     A.ok = A.id = 0; 
115     q.push(A);
116     while(!q.empty()){
117         Point now = q.top();
118         q.pop();
119         // cerr<<now.x<<" "<<now.y<<" "<<now.dis<<" "<<now.ok<<" now"<<endl;
120         if(now.ok){
121             // cerr<<now.x<<" "<<now.y<<endl;
122             printf("%.8f\n",now.dis);
123             break;
124         }
125         for(int i = 1;i<=n;++i){
126             for(int k = 0;k<pol[i].size() - 1;++k){
127                 int idb = pol[i][k].id;
128                 if(now.id){
129                     if(dis[now.id][idb] != inf && now.dis + dis[now.id][idb] < ans[idb]){
130                         ans[idb] = now.dis + dis[now.id][idb];
131                         Point tem = pol[i][k];
132                         tem.dis = ans[idb];
133                         tem.ok = 0;
134                         // cerr<<tem.dis<<" "<<tem.x<<" "<<tem.y<<" ans"<<endl;
135                         q.push(tem);
136                     }
137                 }
138                 else{
139                     if(access(now,pol[i][k]) && now.dis + dist(pol[i][k],now) < ans[idb]){
140                         ans[idb] = now.dis + dist(now,pol[i][k]);
141                         // cerr<<idb<<" "<<dist(pol[i][k],now)<<endl;
142                         Point tem = pol[i][k];
143                         tem.dis = ans[idb];
144                         tem.ok = 0;
145                         // cerr<<tem.x<<" "<<tem.y<<" "<<tem.dis<<" idb"<<endl;
146                         q.push(tem);
147                     }
148                 }
149             }
150         }
151         for(int i = 1;i<=n;++i){
152             for(int k = 0;k<pol[i].size()-1;++k){
153                 if(can[pol[i][k].id] && ( dot(pol[i][k],p0,now) < eps) ){
154                     Point tem = footOfLine(Line(p0,pol[i][k]) , now );
155                     tem.dis = now.dis + dist(now,tem);
156                     // cerr<<"okk"<<endl;
157                     // cerr<<tem.dis<<endl;
158                     tem.id =  0 , tem.ok = 1;
159                     // cerr<<tem.x<<" "<<tem.y<<" "<<tem.dis<<" tem"<<endl;
160                     q.push(tem);
161                 }
162             }
163         }
164     }
165     // cerr<<"fuck"<<endl;
166 }
167 int main(){
168     // cerr<<sqrt(5)<<endl;
169     A.x = 0, A.y = 0;
170     while(~scanf("%d",&n) && n){
171         cnt = 0;
172         scanf("%lf %lf",&p0.x,&p0.y);
173         for(int i = 1;i<=n;++i){
174             pol[i].clear();
175             int m; scanf("%d",&m);
176             Point tem;
177             for(int j = 1;j<=m;++j){
178                 scanf("%lf %lf",&tem.x,&tem.y);
179                 tem.id = ++cnt;
180                 ans[cnt] = inf;
181                 can[cnt] = 0;
182                 pol[i].push_back(tem);
183             }
184             pol[i].push_back(pol[i][0]);
185         }
186         if(access(p0,A) == 0){
187             printf("0.00000000\n");
188             continue;
189         }
190         // cerr<<"here"<<endl;
191         solve();
192     }
193 }
View Code

 

2020.4.11 第五题:Symmetry

题意:给你一个简单多边形,顺序乱序,问你这个是否轴对称图形。

我们枚举第一个点的对称点,然后再On判断即可,记得还要判断轴上的点是否大于2个。

假如第一个点在轴上?没关系,因为轴上的点不可能大于2个,不然多边形自交,所以我们同样工作做三次即可。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-6
  4 const double inf = 1e30;
  5 const int N = 1000+8;
  6 const double pi = acos(-1.0);
  7 struct Point{
  8     double x,y;
  9     Point operator - (const Point& b)const{
 10         return (Point){x-b.x,y-b.y};
 11     }
 12     Point operator + (const Point& b)const{
 13         return (Point){x+b.x,y+b.y};
 14     }
 15     Point operator * (const double& b)const{
 16         return (Point){b*x,b*y};
 17     }
 18     bool operator < (const Point& b)const{
 19         if(x == b.x) return y < b.y;
 20         return x < b.x;
 21     }
 22     double mul(const Point& b)const{
 23         return x*b.x + b.y*y;
 24     }
 25     void near(){
 26         int cx = ceil(x) , fx = floor(x);
 27         int cy = ceil(y) , fy = floor(y);
 28         if( fabs(cx - x) < eps ) x = cx;
 29         else if(fabs(fx - x) < eps) x = fx;
 30         else x = inf;
 31         
 32         if(fabs(cy - y) < eps) y = cy;
 33         else if(fabs(fy - y) < eps ) y = fy;
 34         else y = inf;
 35     }
 36 }p[N];
 37 bool show;
 38 struct Line{
 39     Point s,e;
 40 };
 41 map<Point,int> has;
 42 int n; 
 43 int sgn(double x){
 44     if(fabs(x) < eps ) return 0;
 45     if( x>0 ) return 1;
 46     return -1;
 47 }
 48 double cross(Point a,Point b,Point c){
 49     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
 50 }
 51 double dist2(Point a,Point b){
 52     return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
 53 }
 54 double dot(Point a,Point b,Point c){
 55     return (b.x-a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y);
 56 }
 57 Point projection(Line l,Point p){
 58     double t = dot(l.s,p,l.e) / dist2(l.s,l.e);
 59     return l.s + (l.e - l.s) * t;
 60 }
 61 Point reflection(Line l,Point p){
 62     return p + (projection(l,p) - p) * 2;
 63 }
 64 bool onLine(Point a,Point b,Point c){
 65     return sgn(cross(a,b,c)) == 0;
 66 }
 67 bool judge(Point s,Point e,Point a,Point b){
 68     Point mid = (a+b)*0.5;
 69     return onLine(s,e,mid) && (sgn( (e-s).mul(b-a) ) == 0) ;
 70 }
 71 bool solve(){
 72     int cnt = 0;
 73     for(int cas = 1;cas<=3;++cas){
 74         for(int k = 2;k<=n;++k){
 75             cnt = 0;
 76             Point a = (p[1] + p[k]) * 0.5;
 77             Point b = p[k] - p[1];
 78             swap(b.x,b.y);
 79             b.x = -b.x;
 80             b = a + b;
 81             Line l = (Line){a,b};
 82             for(int i = 1;i<=n;++i) has[ p[i] ] = 1;
 83             has[ p[1] ] = has[ p[k] ] = 0;
 84             bool ok = 1;
 85             for(int i = 1;i<=n && ok;++i){
 86                 if(has[p[i]] == 0) continue;
 87                 Point tem = reflection(l,p[i]);
 88                 tem.near();
 89                 if(tem.x == inf || tem.y == inf || (has[tem] == 0)) ok = 0;
 90                 if(judge(l.s,l.e,p[i],tem) == 0) ok = 0;
 91                 has[tem] = has[p[i]] = 0;
 92                 if(tem.x == p[i].x && tem.y == p[i].y) ++cnt;
 93             }
 94             if(ok && cnt<=2) return 1;
 95         }
 96 
 97         Point tem = p[1];
 98         for(int i =1;i<n;++i) p[i] = p[i+1];
 99         p[n] = tem;
100     }
101     return 0;
102 }
103 bool all_Line(){
104     for(int i = 3;i<=n;++i){
105         if( sgn( cross(p[1],p[2],p[i]) ) != 0 ) return 0;
106     }
107     return 1;
108 }
109 int main(){
110     scanf("%d",&n);
111     for(int i =  1;i<=n;++i) scanf("%lf %lf",&p[i].x,&p[i].y);
112     if(all_Line()){
113         puts("No");
114         return 0;
115     }
116     if(solve()) puts("Yes");
117     else puts("No");
118     return 0;
119 }
View Code

 

2020.4.12 第六题:集训队训练:Forest protection

这题虽然到最后很少人过,但是其实很简单,直接当作签到题秒了,就求个凸包然后旋转卡壳一下好了。。

 1 #include<bits/stdc++.h>
 2 using namespace  std;
 3 typedef long long ll;
 4 const int N = 1e5+9;
 5 struct Point{
 6     ll x,y;
 7     bool operator < (const Point& b)const{
 8         return x < b.x || (x==b.x && y < b.y);
 9     }
10     Point operator - (const Point& b)const{
11         return (Point){x-b.x,y-b.y};
12     }
13     ll cro(Point b){
14         return x*b.y - b.x*y;
15     }
16     ll dot(Point b){
17         return x*b.x + y * b.y;
18     }
19 }p[N],ch[N*2];
20 int n; 
21 ll cross(Point a,Point b,Point c){
22     return (b.x - a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
23 }
24 int Andrew(){
25     sort(p,p+n);
26     int m = 0;
27     for(int i = 0;i<n;++i){
28         while( m>1 && cross(ch[m-2],p[i],ch[m-1]) > 0 ) --m;
29         ch[m++] = p[i];
30     }
31     int k = m;
32     for(int i = n-2;i>=0;--i){
33         while( m>k && cross(ch[m-2],p[i],ch[m-1]) >0 ) --m;
34         ch[m++] = p[i];
35     }
36     if(n>1) --m;
37     return m;
38 }
39 bool all_line(){
40     for(int i = 2;i<n;++i){
41         if(cross(p[0],p[1],p[i]) != 0) return 0;
42     }
43     return 1;
44 }
45 int main(){
46     scanf("%d",&n);
47     for(int i = 0;i<n;++i) scanf("%lld %lld",&p[i].x,&p[i].y);
48     if( all_line() ){
49         printf("%d",n);
50         return 0;
51     }
52     int m = Andrew();
53     int ans = 0;
54     for(int i = 0;i<m;++i) ch[i+m] = ch[i];
55     int j = 0;
56     for(int i = 0;i<m;++i){
57         while( j<i+m && ( ( (ch[i+1] - ch[i]).cro(ch[j+1] - ch[j]) == 0) && ( ch[i+1] - ch[i]).dot(ch[j+1] - ch[j]) > 0 ) ) ++j;
58         while( j < i+m && (ch[i+1] - ch[i]).cro(ch[j+1] - ch[j]) > 0 ) ++j;
59         // cerr<<ch[i].x<<" "<<ch[i].y<<" "<<ch[j].x<<" "<<ch[j].y<<" "<<i<<" "<<j<<endl;
60         ans = max(j - i -1,ans);
61     }
62     printf("%d",m - ans);
63     return 0;
64 }
View Code

 

2020.4.13 第七题(H): Cornering at Poles

题意:给你8个圆,问你从原点走到终点,不能经过任意圆的最短距离。

这题是一道寻路问题的经典题目。其实不是很难,但是老是写挂细节,搞得心态崩了。。。写了两天。

就是很明显,我两个点的最短距离肯定就是点到圆的切线,圆上的弧,两圆切线。可以想像一下一根直线拉直。

然后就是把模板抄上去,建图跑dij就好了。 注意:弧上两点判断是否可以达到,只需要判断两个点是不是在某一个圆里,或者某一个圆的圆心极角在 两点极角之间,然后 可以那部分圆弧就取min就好了。

可以把关键点全部扣出来,然后n方建边,也可以边扣关键点边建边。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-8
  4 #define pii pair<double,int> 
  5 const double inf = 1e50;
  6 const double pi = acos(-1.0);
  7 const int N = 1e5+9;
  8 double R;
  9 int sgn(double x){
 10     if(fabs(x) < eps) return 0;
 11     if( x > 0 ) return 1;
 12     return -1;
 13 } 
 14 struct Point{
 15     double x,y;
 16     Point operator - (const Point& b)const{
 17         return (Point){x-b.x,y-b.y};
 18     }
 19     Point operator + (const Point& b)const{
 20         return (Point){ x + b.x,y+b.y};
 21     }
 22     Point operator * (const double& b)const{
 23         return (Point){x*b,y*b};
 24     }
 25     Point operator / (const double& b)const{
 26         return (Point){x/b,y/b};
 27     }
 28 }p[N];
 29 
 30 double cross(Point a,Point b,Point c){
 31     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
 32 }
 33 double dot(Point a,Point b,Point c){
 34     return (b.x - a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y);
 35 }
 36 double dist2(Point a,Point b){
 37     return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
 38 }
 39 double dist(Point a,Point b){
 40     return sqrt(dist2(a,b));
 41 }
 42 double Point_to_Seg(Point p,Point a,Point b){
 43     if( sgn( dot(a,p,b) ) < 0 ) return dist(p,a);
 44     if( sgn( dot(b,p,a) ) < 0 ) return dist(p,b);
 45     return fabs( cross(p,a,b) ) / dist(a,b);
 46 }
 47 struct Circle{
 48     Point o;
 49     vector<int> v;
 50     Point getPoint(double deta){
 51         return (Point){o.x + cos(deta)*R , o.y + sin(deta)*R };
 52     }
 53     bool is_insert(Point a,Point b){
 54         double d;
 55         if( dist(a,b) < eps ) d = dist(a,o);
 56         else d = Point_to_Seg(o,a,b);
 57         if( sgn(d  - R) < 0 ) return 1;
 58         return 0;
 59     }
 60 }cir[10];
 61 int cnt;
 62 int bel[N];
 63 vector< pair<int,double> > G[N];
 64 double dis[N];
 65 Point a[10],b[10];
 66 int n; 
 67 int getTangentPoints(Point p,Circle c,Point& r1,Point& r2){
 68     double d = dist(p,c.o);
 69     if( sgn(d-R) < 0 ) return 0;
 70     else if( sgn(d-R) == 0 ){
 71         r1 = p;        
 72         return 1;
 73     }
 74     else{
 75         double base = atan2(p.y - c.o.y,p.x - c.o.x);
 76         double deta = acos( R/d );
 77         r1 = c.getPoint(base - deta);
 78         r2 = c.getPoint(base + deta);
 79         return 2;
 80     }
 81 }
 82 int getCircleTangents(Circle A,Circle B,Point* a,Point* b){
 83     int cnt = 0;
 84     double d2 = dist2(A.o,B.o);
 85     double rsum = 2*R;
 86     double base = atan2(B.o.y - A.o.y,B.o.x - A.o.x);
 87     double ang = acos(0.0);
 88     a[cnt] = A.getPoint(base+ang); b[cnt] = B.getPoint(base+ang); cnt++;
 89     a[cnt] = A.getPoint(base-ang); b[cnt] = B.getPoint(base-ang); cnt++;
 90 
 91     if( sgn(d2 - rsum*rsum) > 0 ){
 92         ang = acos( 2*R/ sqrt(d2) );
 93         a[cnt] = A.getPoint(base + ang); b[cnt] = B.getPoint(pi+base + ang); ++cnt;
 94         a[cnt] = A.getPoint(base - ang); b[cnt] = B.getPoint(pi+base - ang); ++cnt;
 95     }
 96     return cnt;
 97 }
 98 bool road_ok(Point a,Point b){
 99     for(int i = 1;i<=n;++i){
100         if( cir[i].is_insert(a,b) ) return 0;
101     }
102     return 1;
103 }
104 // double relative(double a){
105 //     if( a < -pi ) a += 2*pi;
106 //     else if( a > pi) a -= 2*pi;
107 //     return a;
108 // }
109 double rad_ok(int k,Point a,Point b){
110     Circle c = cir[k];
111     double le = atan2(a.y - c.o.y,a.x - c.o.x);
112     double ri = atan2(b.y - c.o.y,b.x - c.o.x);
113     if( le > ri ) swap(le,ri);
114     bool ok1 = 1, ok2 = 1;
115     for(int i = 1;i<=n;++i){
116         if( dist(a,cir[i].o) < R - eps || dist( b,cir[i].o) < R - eps ) return inf;
117         double d = dist(cir[i].o,cir[k].o);
118         if( i == k || dist(cir[i].o,c.o) > 2*R - eps) continue;
119         Point w = (cir[i].o - cir[k].o) / d * 100.0 + cir[k].o;
120         // double phi = atan2( cir[i].o.y - c.o.y , cir[i].o.x - c.o.x);
121         double phi = atan2(w.y-c.o.y,w.x - c.o.x);
122         if( sgn(phi - le) > 0  && sgn(phi - ri) < 0 ) ok1 = 0;
123         else ok2 = 0;
124     }
125     double res = inf;
126     // cerr<<(ri-le)*R<<" "<<(2*pi - ri + le)*R<<" !!!"<<ok1<<" "<<ok2<<endl;
127     if(ok1) res = min(res,(ri - le)*R );
128     if(ok2) res = min(res, (2*pi - ri + le) * R);
129     return res;
130 }
131 void build_G(){
132     for(int i = 1;i<=n;++i){
133         Point r1,r2;
134         int m = getTangentPoints(p[1],cir[i],r1,r2);
135         if( m == 0 ) return;
136         if(m>=1 ){
137             p[++cnt] = r1; bel[cnt] = i;
138         }
139         if(m >= 2){
140             p[++cnt] = r2; bel[cnt] = i;
141         }
142 
143         m = getTangentPoints(p[2],cir[i],r1,r2);
144         if( m == 0 ) return;
145         if(m>=1 ){
146             p[++cnt] = r1; bel[cnt] = i;
147         }
148         if(m >= 2){
149             p[++cnt] = r2; bel[cnt] = i;
150         }
151     }
152 
153     for(int i = 1;i<=n;++i){
154         for(int j = i+1;j<=n;++j){
155             int m = getCircleTangents(cir[i],cir[j],a,b);
156             for(int k = 0;k<m;++k){
157                     p[++cnt] = a[k]; bel[cnt] = i;
158                     p[++cnt] = b[k]; bel[cnt] = j;
159             }
160         }
161     }
162     for(int i = 1;i<=cnt;++i){
163         for(int j = i+1;j<=cnt;++j){
164             if( bel[i] == bel[j] ){
165                 double d = rad_ok(bel[i],p[i],p[j]);
166                 // cerr<<i<<" "<<j<<" "<<d<<endl;
167                 if( d != inf ){
168                     G[i].push_back({j,d});
169                     G[j].push_back({i,d});
170                 }
171             }
172             else{    
173                 if(road_ok(p[i],p[j])){
174                     G[i].push_back({j,dist(p[i],p[j])});
175                     G[j].push_back({i,dist(p[i],p[j])});
176                 }
177             }
178         }
179     }
180 }
181 void dij(){
182     for(int i = 1;i<=cnt;++i) dis[i] = inf;
183     dis[1] = 0;
184     priority_queue<pii,vector<pii>,greater<pii> > q;
185     q.push(make_pair(0,1));
186     while(!q.empty()){
187         int u = q.top().second;
188         double tem = q.top().first;
189         q.pop();
190         if( tem > dis[u] + eps ) continue;
191         for(auto it : G[u]){
192             int v = it.first;
193             double w = it.second;
194             if( dis[v] - eps > dis[u] + w){
195                 dis[v] = dis[u] + w;
196                 q.push( make_pair(dis[v],v) );
197             }
198         }
199     }
200 }
201 int main(){
202     R = 100.0;
203     scanf("%d",&n);
204     scanf("%lf %lf",&p[2].x,&p[2].y);
205     p[1].x = p[1].y = 0;
206     bel[1] = 0 , bel[2] = n+1;
207     cnt = 2;
208     for(int i = 1;i<=n;++i){
209         scanf("%lf %lf",&cir[i].o.x,&cir[i].o.y);
210     }
211     build_G();
212     dij();
213 
214     if( dis[2] == inf ) printf("0.0");
215     else printf("%.5f",dis[2]);
216     return 0;
217 }
218 /*
219 1 958 834
220 86 57
221 */
View Code

 

2020.4.15.第八题:hdu4785

这题真的难顶,前前后后挂了很多次,可能也是因为晚上思维下降的原因吧。为这题专门写了一个博客:https://www.cnblogs.com/xiaobuxie/p/12712701.html

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-8
  4 const int N = 1e3+9;
  5 const double inf = 1e6;
  6 int sgn(double x){
  7     if( fabs(x) < eps) return 0;
  8     if( x < 0 ) return -1;
  9     return 1;
 10 }
 11 struct Point{
 12     double x,y;
 13     Point operator - (const Point& b)const{
 14         return (Point){x-b.x,y-b.y};
 15     }
 16     Point operator + (const Point& b)const{
 17         return (Point){x+b.x,y+b.y};
 18     }
 19     bool operator < (const Point& b)const{
 20         if( sgn(x - b.x) == 0 ) return y < b.y;
 21         return x < b.x;
 22     }
 23 }va[N],vb[N],rec[10];
 24 double cross(Point a,Point b){
 25     return a.x * b.y - b.x * a.y;
 26 }
 27 vector<Point> a[N],b[N];
 28 int n;
 29 double xl,yl,xr,yr;
 30 double X[N];
 31 double mi[N],mx[N];
 32 int cnt;
 33 bool insert(Point a,Point b,Point c,Point d){
 34     return 
 35         max(a.x,b.x) >= min(c.x,d.x) &&
 36         max(c.x,d.x) >= min(a.x,b.x) &&
 37         max(a.y,b.y) >= min(c.y,d.y) &&
 38         max(c.y,d.y) >= min(a.y,b.y) &&
 39         sgn(cross(c-a,b-a))*sgn(cross(d-a,b-a))<=0 &&
 40         sgn(cross(a-c,d-c))*sgn(cross(b-c,d-c))<=0;
 41 }
 42 Point segcross(Point a,Point b,Point c,Point d){
 43     double u = cross(b-a,c-a) , v = cross(a-b,d-b);
 44     return (Point){ (c.x*v+d.x*u)/(u+v) , (c.y*v+d.y*u)/(u+v)};
 45 }
 46 vector<Point> Minke(vector<Point> pa,vector<Point> pb){
 47     int na = pa.size(),nb = pb.size();
 48     //
 49     int ida = 0, idb = 0;
 50     for(int i = 0;i<na;++i) if(pa[i] < pa[ida]) ida = i;
 51     for(int i = 0;i<nb;++i) if(pb[i] < pb[idb]) idb = i;
 52     vector<Point> ta , tb;
 53     for(int i = 0;i<na;++i){
 54         ta.push_back(pa[ida]);
 55         ida = (ida+1)%na;
 56     }
 57     for(int i = 0;i<nb;++i){
 58         tb.push_back(pb[idb]);
 59         idb = (idb+1)%nb;
 60     }
 61     pa = ta; pb = tb;
 62 
 63     for(int i = 0 ; i < na-1;++i) va[i] = pa[i+1] - pa[i];
 64     va[na-1] = pa[0] - pa[na-1];
 65     for(int i = 0 ; i < nb-1;++i) vb[i] = pb[i+1] - pb[i];
 66     vb[nb-1] = pb[0] - pb[nb-1];
 67     vector<Point> pc;
 68     Point tem;
 69     tem = pa[0] + pb[0];
 70     pc.push_back(tem);
 71     int p1 = 0, p2 = 0;
 72     while(p1 < na && p2 < nb){
 73         tem = tem + ( (cross(va[p1],vb[p2]) >= 0 ) ? va[p1++] : vb[p2++]);
 74         pc.push_back(tem);
 75     }
 76     while(p1 < na){
 77         tem = tem + va[p1++];
 78         pc.push_back(tem);
 79     }
 80     while(p2 < nb){
 81         tem = tem + vb[p2++];
 82         pc.push_back(tem);
 83     }
 84     //
 85     return pc;
 86 }
 87 void init(){
 88     double xmi = a[n+1][0].x,ymi = a[n+1][0].y,xmx = xmi , ymx = ymi;
 89     for(auto it : a[n+1]){
 90         xmi = min(xmi,it.x) , xmx = max(xmx,it.x);
 91         ymi = min(ymi,it.y) , ymx = max(ymx,it.y);
 92     }
 93     xl -= xmi; xr -= xmx;
 94     yl -= ymi; yr -= ymx;
 95 
 96     for(int i = 0;i<a[n+1].size();++i){
 97         a[n+1][i].x = -a[n+1][i].x;
 98         a[n+1][i].y = -a[n+1][i].y;
 99     }
100     for(int i = 1;i<=n;++i){
101         b[i] = Minke(a[n+1],a[i]);
102     }
103     for(int i = 1;i<=n;++i){
104         mi[i] = b[i][0].x , mx[i] = mi[i];
105         for(auto it : b[i]){
106             mi[i] = min(mi[i],it.x);
107             mx[i] = max(mx[i],it.x);
108         }
109     }
110     X[++cnt] = xl;
111     X[++cnt] = xr;
112     for(int i = 1;i<=n;++i){
113         for(auto it : b[i]){
114             if(it.x < xl + eps || it.x > xr - eps ) continue;
115             X[++cnt] = it.x;
116         }
117     }
118     for(int i = 1;i<=n;++i){
119         for(int j = i+1;j<=n;++j){
120             for(int ii = 0;ii<b[i].size()-1;++ii){
121                 for(int jj = 0;jj<b[j].size()-1;++jj){
122                     Point s1 = b[i][ii] , e1 = b[i][ii+1];
123                     Point s2 = b[j][jj] , e2 = b[j][jj+1];
124                     if( sgn(cross(e1 - s1,s2 - s1) ) == 0 && sgn(cross(e1 - s1,e2 - s1) == 0 ) ) continue;
125                     if( insert(s1,e1,s2,e2) ){
126                         Point tem = segcross(s1,e1,s2,e2);
127                         if(tem.x < xl + eps || tem.x > xr - eps ) continue;
128                         X[++cnt] = tem.x;
129                     }
130                 }
131             }
132         }
133     }
134     rec[0] = (Point){xl,yl}; rec[1] = (Point){xr,yl};
135     rec[2] = (Point){xr,yr}; rec[3] = (Point){xl,yr}; rec[4] = rec[0];
136     for(int i = 1;i<=n;++i){
137         for(int j = 0;j<b[i].size()-1;++j){
138             for(int k = 0;k<4;++k){
139                 if(insert(b[i][j],b[i][j+1],rec[k],rec[k+1])){
140                     Point res = segcross(b[i][j],b[i][j+1],rec[k],rec[k+1]);
141                     X[++cnt] = res.x;
142                 }
143             }
144         }
145     }
146     sort(X+1,X+1+cnt);
147 }
148 void crosspol(vector<Point> p, double xx , vector< pair<double,int> >& Y){
149     Point le = (Point){xx,-inf} , ri = (Point){xx,inf};
150     vector<double> vec;
151     for(int j = 0;j<p.size()-1;++j){
152         if( sgn( p[j].x - le.x) == 0 && sgn(p[j+1].x - le.x) == 0){
153             vec.push_back(p[j].y);
154             vec.push_back(p[j+1].y);
155         }
156         else{
157             if(insert(le,ri,p[j],p[j+1]) ){
158                 Point tem = segcross(le,ri,p[j],p[j+1]);
159                 vec.push_back(tem.y);
160             }
161         }
162     }
163     sort(vec.begin(),vec.end());
164     if(vec.size() < 2) return;
165     double ya = vec[0] , yb = vec[vec.size()-1];
166     Y.push_back({max(ya,yl),1}); Y.push_back({min(yb,yr),-1});
167 }
168 double solve_len(vector< pair<double,int> > Y){
169     sort(Y.begin(),Y.end());
170     int num = 0;
171     double res = 0;
172     double las;
173     for(auto it : Y){
174         if(num==0 && it.second == 1){
175             las = it.first;
176             ++num;
177             continue;
178         }
179         num += it.second;
180         if(num == 0 && it.second == -1) res += (it.first - las);
181     }
182     return res;
183 }
184 void solve(){
185     double ans = 0;
186     for(int i = 1;i<cnt;++i){
187         vector< pair<double,int> > Yl,Yr;
188         for(int j = 1;j<=n;++j){
189             if(mx[j] < X[i] + eps || mi[j] > X[i+1] - eps ) continue;
190             crosspol(b[j],X[i],Yl);
191             crosspol(b[j],X[i+1],Yr);
192         }
193         double le = solve_len(Yl) , ri = solve_len(Yr);
194         ans += (ri + le) * (X[i+1] - X[i]) * 0.5;
195     }
196     printf("%.3f\n",(xr-xl)*(yr-yl) - ans);
197     return;
198 }
199 int main(){
200     int T; scanf("%d",&T);
201     for(int cas = 1;cas <= T;++cas){
202         cnt = 0;
203         printf("Case #%d: ",cas);
204         scanf("%d",&n);
205         for(int i = 1;i<=n+1;++i){
206             a[i].clear();
207             int m; scanf("%d",&m);
208             for(int j = 1;j<=m;++j){
209                 Point tem;
210                 scanf("%lf %lf",&tem.x,&tem.y);
211                 a[i].push_back(tem);
212             }
213         }
214         scanf("%lf %lf %lf %lf",&xl,&yl,&xr,&yr);
215         init();
216         solve();
217     }
218     return 0;
219 }
220 /*
221 6
222 1
223 3
224 0 0
225 10 0
226 10 10
227 4
228 0 0
229 1 0
230 1 1
231 0 1
232 0 0 10 10
233 */
View Code

 

2020.4.19 第九题:http://codeforces.com/group/uVAsoW2Jkj/contest/276618

这是我们的训练赛。 I 题是计几,题意:空间给你两个三角形,判断两个三角形最短距离。

由于我没有三维计几板子,然后直接炸裂,被迫写了个三分,(因为答案肯定是一个边和一个面距离,所以三分边,转换成点到三角形距离,然后T成傻逼了,结束之后队友爬山算法加各种优化帮我2.8s卡过去了)。

正解:先判断三角形是否相交,相交就0,否则就是顶点到另一个三角形距离,以及线段距离,这个很显然。然后就是上板子的事情了。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-7
  4 const double pi = acos(-1.0);
  5 int sgn(double x){
  6     if( fabs(x) < eps ) return 0;
  7     if( x > 0 ) return 1;
  8     return -1;
  9 }
 10 struct Point{
 11     double x,y,z;
 12     Point operator - (const Point& b)const{
 13         return (Point){x-b.x,y-b.y,z-b.z};
 14     }
 15     Point operator + (const Point& b)const{
 16         return (Point){x+b.x,y+b.y,z+b.z};
 17     }
 18     Point operator * (const double& b)const{
 19         return (Point){b*x,b*y,b*z};
 20     }
 21     Point operator / (const double& b)const{
 22         return (Point){x/b,y/b,z/b};
 23     }
 24     double len(){return sqrt(x*x+y*y+z*z); }
 25 }T1[4],T2[4];
 26 Point cross(Point a,Point b){
 27     double xx = a.y*b.z-b.y*a.z;
 28     double yy = a.x*b.z-b.x*a.z;
 29     double zz = a.x*b.y-b.x*a.y;
 30     return (Point){xx,-yy,zz};
 31 }
 32 double dot(Point a,Point b){
 33     return a.x*b.x + a.y*b.y + a.z*b.z;
 34 }
 35 
 36 bool SameSide(Point p1,Point p2,Point a,Point b){
 37     return dot(cross(b - a, p1 - a), cross(b - a, p2 - a)) - eps >= 0;
 38 }
 39 bool PointInTri(Point P, Point P0, Point P1,Point P2){
 40     return SameSide(P, P0, P1, P2) && SameSide(P, P1, P0, P2) && SameSide(P, P2, P0, P1);
 41 }
 42 
 43 // 三角形P0P1P2是否和线段AB相交
 44 bool TriSegIntersection(Point P0, Point P1,  Point P2, Point A, Point B, Point & P){
 45     Point n = cross(P1 - P0, P2 - P0);
 46     if(abs(dot(n, B - A)) <= eps)  return false;    // 线段A-B和平面P0P1P2平行或共面
 47     else   // 平面A和直线P1-P2有惟一交点
 48     {
 49         double t = dot(n, P0 - A) / dot(n, B - A);
 50         if(t + eps < 0 || t - 1 - eps > 0)  return false;    // 不在线段AB上
 51         P = A + (B - A) * t; // 交点
 52         return PointInTri(P, P0, P1, P2);
 53     }
 54 }
 55 //空间两三角形是否相交
 56 bool TriTriIntersection(Point * T1, Point * T2){
 57     Point P;
 58     for(int i = 0; i < 3; i++){
 59         if(TriSegIntersection(T1[0], T1[1], T1[2], T2[i], T2[(i + 1) % 3], P))
 60         {
 61             return true;
 62         }
 63  
 64         if(TriSegIntersection(T2[0], T2[1], T2[2], T1[i], T1[(i + 1) % 3], P))
 65         {
 66             return true;
 67         }
 68     }
 69  
 70     return false;
 71 }
 72 
 73 
 74 //点到线段的距离
 75 double point_to_seg(Point p, Point a, Point b){
 76     if((a-b).len()<eps) return (p - a).len();          //xiugai
 77     Point v1 = b - a, v2 = p - a, v3 = p - b;
 78     if(dot(v1, v2) + eps < 0)  return v2.len();
 79     else{
 80         if(dot(v1, v3) - eps > 0) return v3.len();
 81         else return cross(v1, v2).len() / v1.len();
 82     }
 83 }
 84 
 85 
 86 double point_to_tri(Point p,Point a,Point b,Point c){
 87     if(PointInTri(p,a,b,c)){
 88         Point n = cross(b-a,c-a);
 89         return fabs( dot( p-a ,n ) ) / n.len() ;
 90     }
 91     else{
 92         double res = point_to_seg(p,a,b);
 93         res = min(res,point_to_seg(p,a,c));
 94         res = min(res,point_to_seg(p,b,c));
 95         return res;
 96     }
 97 }
 98 
 99 // // 两线段距离
100 // double SegDis(Point a, Point b, Point c, Point d) {
101 //     Point n = cross(a - b, c - d);
102 //     if (sgn(n.len()) != 0) {
103 //         n = n / n.len();                                                /// xiugai
104 //         Point cc = GetPlaneProjection(c, a, n);
105 //         Point dd = GetPlaneProjection(d, a, n);
106 //         Point res;
107 //         if (SegCross(a, b, cc, dd, res) == 1)
108 //             return LineDis(a, b, c, d);
109 //     }
110 //     double ret = point_to_seg(a, c, d);
111 //     ret = min(ret, point_to_seg(b, c, d));
112 //     ret = min(ret, point_to_seg(c, a, b));
113 //     ret = min(ret, point_to_seg(d, a, b));
114 //     return ret;
115 // }
116 
117 //线段之间距离 
118 double seg_to_seg(Point a,Point b,Point c,Point d){
119     double res = min( point_to_seg(a,c,d) , point_to_seg(b,c,d) );
120     res = min( res , min( point_to_seg(c,a,b) , point_to_seg(d,a,b) ) );
121     Point normal = cross(b-a, d-c);
122     double cp1 = dot(normal, cross( d-c, a-c) );
123     double cp2 = dot(normal, cross( d-c, b-c) );
124     double cp3 = dot(normal, cross( b-a, c-a) );
125     double cp4 = dot(normal, cross( b-a, d-a) );
126     if (cp1*cp2 < -eps && cp3*cp4 < -eps ) {
127         Point p1 = (b*cp1 - a*cp2) / (cp1-cp2);
128         Point p2 = (d*cp3 - c*cp4) / (cp3-cp4);
129         res = min(res, (p2-p1).len());
130     }
131     return res;
132 }
133           
134 int main(){
135     int T; scanf("%d",&T);
136     while(T--){
137         scanf("%lf %lf %lf %lf %lf %lf %lf %lf %lf",&T1[0].x,&T1[0].y,&T1[0].z,&T1[1].x,&T1[1].y,&T1[1].z,&T1[2].x,&T1[2].y,&T1[2].z);
138         scanf("%lf %lf %lf %lf %lf %lf %lf %lf %lf",&T2[0].x,&T2[0].y,&T2[0].z,&T2[1].x,&T2[1].y,&T2[1].z,&T2[2].x,&T2[2].y,&T2[2].z);
139         if(TriTriIntersection(T1,T2)){
140             printf("0.000000000\n");
141             continue;
142         }
143         double ans = 1e60;
144         for(int i = 0;i<3;++i) ans = min(ans,point_to_tri(T1[i],T2[0],T2[1],T2[2]) );
145         for(int i = 0;i<3;++i) ans = min(ans,point_to_tri(T2[i],T1[0],T1[1],T1[2]) );
146         for(int i = 0;i<3;++i){
147             for(int j = 0;j<3;++j){
148                 ans = min(ans,seg_to_seg(T1[i],T1[(i+1)%3] , T2[j],T2[(j+1)%3]));
149             }
150         }
151         printf("%.9f\n",ans);
152     }
153     return 0;
154 }
View Code

 

2020.4.20 第十题:cf1218B

这题就是给你n个仓库(凸多边形),原点有个镭射眼,可以透过一面墙看到仓库,问你看到仓库的最大面积是多少。

这题其实就直接是扫面线,因为两个线段的相对位置不会因为扫描线改变而改变,所以我们用set来维护靠近原点最近的线段,然后每次往set里面加减线段,找前两个线段统计答案就好。

这题不知道为什么一定要用long double 才能过。。。。。卡了很久,,,,

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N = 5e4+8;
  4 #define double long double
  5 const double eps = 1e-9;
  6 const double pi = acos(-1.0);
  7 const double inf = 1e6;
  8 int cnt;
  9 int segcnt = 0;
 10 double curang;
 11 struct Point{
 12     double x,y;
 13     double corss(Point b)const{
 14         return x * b.y - b.x * y;
 15     }
 16     Point operator - (const Point& b)const{
 17         return (Point){x-b.x,y-b.y};
 18     }
 19     double len(){return sqrt(x*x+y*y);}
 20 };
 21 Point segcross(Point a,Point b,Point c,Point d,bool& ok ){
 22     double u = (b-a).corss(c-a) , v = (a-b).corss(d-b);
 23     if( fabs(u+v) < eps){
 24         ok = 0;
 25         Point tem = {-1,-1};
 26         return tem;
 27     }
 28     ok = 1;
 29     return (Point){ (c.x*v + d.x*u)/(u+v) , (c.y*v + d.y*u)/(u+v) };
 30 }
 31 struct Seg{
 32     Point a,b;
 33     int id;
 34     bool operator < (const Seg& s)const{
 35         bool ok1 ,ok2;
 36         Point c = (Point){cos(curang) , sin(curang)};
 37         Point o = (Point){0,0};
 38         Point cr1 = segcross(a,b,o,c,ok1);
 39         Point cr2 = segcross(s.a,s.b,o,c,ok2);
 40         // if( ok1 == 0 || ok2 == 0 ) return id < s.id;
 41         // assert(ok1 && ok2);
 42         if( fabs( cr1.len() - cr2.len() ) < eps ) return id < s.id;
 43         return cr1.len() < cr2.len();
 44     }
 45 };
 46 vector<Point> pol[N];
 47 double ang[N];
 48 vector<int> add[N],del[N];
 49 Seg seg[N];
 50 
 51 void add_seg(Point a,Point b){
 52     double anga = atan2(a.y,a.x) , angb = atan2(b.y,b.x);
 53     if( fabs(anga - angb) < eps ) return;
 54     if( anga > angb + eps ){
 55         swap(anga,angb);
 56         swap(a,b);
 57     }
 58     int pa = lower_bound(ang+1,ang+1+cnt,anga) - ang;
 59     int pb = lower_bound(ang+1,ang+1+cnt,angb) - ang;
 60 
 61     ++segcnt;
 62     seg[segcnt] = (Seg){a,b,segcnt};
 63     if( angb - anga > pi + eps ){
 64         // Point c = segcross(a,b,(Point){-inf,0},(Point){inf,0});
 65         if( fabs(anga + pi) > eps){
 66             // ++segcnt;
 67             // seg[segcnt] = (Seg){c,a,segcnt};
 68             add[1].push_back(segcnt);
 69             del[pa].push_back(segcnt);
 70         }
 71 
 72         if( fabs( angb - pi ) > eps){
 73             // ++segcnt;
 74             // seg[segcnt] = (Seg){b,c,segcnt};
 75             add[pb].push_back(segcnt);
 76             del[cnt].push_back(segcnt);
 77         }
 78     }
 79     else{
 80         add[pa].push_back(segcnt);
 81         del[pb].push_back(segcnt);
 82     }
 83 }
 84 double area(Point a,Point b,Point c,Point d){
 85     double res = 0;
 86     res += (b-a).corss(c-a);
 87     res += (c-a).corss(d-a);
 88     if(res < -eps ) res = -res;
 89     return res * 0.5;
 90 }
 91 void solve(){
 92     set<Seg> st;
 93     double ans = 0;
 94     curang = 0;
 95     for(int i = 1;i<cnt;++i){
 96         for(auto it : del[i] )  st.erase(seg[it]);
 97         curang = ( ang[i] + ang[i+1] ) / 2.0;
 98         for(auto it : add[i])  st.insert(seg[it]);
 99         if((int)st.size() >= 2){
100             // assert((int)st.size()>=2);
101             Seg s1,s2;
102             auto it = st.begin();  s1 = (*it);
103             ++it; s2 = (*it);
104             Point c1 = (Point){inf*cos(ang[i]) , inf * sin(ang[i])};
105             Point c2 = (Point){inf*cos(ang[i+1]) , inf * sin(ang[i+1])};
106             Point o = (Point){0,0};
107             bool ok1,ok2,ok3,ok4;
108             Point a1 = segcross(o,c1,s1.a,s1.b,ok1);
109             Point a2 = segcross(o,c1,s2.a,s2.b,ok2);
110             Point a3 = segcross(o,c2,s2.a,s2.b,ok3);
111             Point a4 = segcross(o,c2,s1.a,s1.b,ok4);
112             // assert(ok1 && ok2 && ok3 && ok4);
113             // if( ok1 == 0 || ok2 == 0 || ok3 == 0 || ok4 == 0) continue;
114             ans += area(a1,a2,a3,a4);
115         }
116     }
117     // printf("%.12f",ans);
118     cout<<ans<<endl;
119 }
120 int main(){
121     int n; cin>>n;
122     for(int i = 1;i<=n;++i){
123         int m; cin>>m;
124         Point tem;
125         for(int j = 1;j<=m;++j){
126             // scanf("%lf %lf",&tem.x,&tem.y);
127             cin>>tem.x>>tem.y;
128             // cerr<<tem.x<<" "<<tem.y<<" !"<<endl;
129             pol[i].push_back(tem);
130             ang[++cnt] = atan2(tem.y,tem.x);
131         }
132         pol[i].push_back(pol[i][0]);
133     }
134     ang[++cnt] = -pi; ang[++cnt] = pi;
135     sort(ang+1,ang+1+cnt);
136     cnt = unique(ang+1,ang+1+cnt) - ang - 1;
137 
138     for(int i = 1;i<=n;++i){
139         for(int k = 0;k<pol[i].size()-1;++k){
140             add_seg(pol[i][k],pol[i][k+1]);
141         }
142     }
143     
144     solve();
145     return 0;
146 }
View Code

 

2020.4.22 第十一题:hdu4805

这题卡了我一天了,这题不知道为什么会挂,然后对着过了的代码改,发现好像是std写挂了???不知道,反着这题挺奇怪的。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-9
  4 // #define double long double
  5 const int N = 1e5+9;
  6 bool vis[N];
  7 int sgn(double x){
  8     if( fabs(x) < eps) return 0;
  9     if( x < 0 ) return -1;
 10     return 1;
 11 }
 12 // double ans,stlen;
 13 struct Point{
 14     double x,y,z;
 15     Point operator - (const Point& b)const{
 16         return (Point){x-b.x,y-b.y,z-b.z};
 17     }
 18     Point operator * (const double& b)const{
 19         return (Point){x*b,y*b,z*b};
 20     }
 21     Point operator / (const double& b)const{
 22         return (Point){x/b,y/b,z/b};
 23     }
 24     Point operator + (const Point& b)const{
 25         return (Point){x+b.x,y+b.y,z+b.z};
 26     }
 27     double len(){return sqrt(x*x+y*y+z*z);}
 28     double len2(){return x*x+y*y+z*z;}
 29 }S,T,dir,Tri[N][5];
 30 int n;
 31 Point cross(Point A, Point B) {
 32     return Point{A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x};
 33 }
 34 double dot(Point a,Point b){
 35     return a.x * b.x + a.y * b.y + a.z* b.z;
 36 }
 37 //点是否在线段上(包括顶点)
 38 bool Point_on_Seg(Point p,Point a,Point b){
 39     return sgn( dot(a-p,b-p) ) <=0 && sgn( cross(a-p,b-p).len() ) == 0;
 40 }
 41 //点是否在直线上
 42 bool Point_on_Line(Point p,Point a,Point b){
 43     return cross(p-a,b-a).len() < eps;
 44 }
 45 bool intersect(Point a,Point b,Point c,Point d){
 46     return sgn( dot( cross(b-a,c-a) , cross(b-a,d-a) ) ) <= 0 && sgn( dot( cross(d-c,a-c) ,cross(d-c,b-c))) <= 0;
 47 }
 48 bool parallel(Point a,Point b,Point c,Point d){
 49     return sgn( cross(a-b,c-d).len() ) == 0;
 50 }
 51 //直线相交判定 0:不相交(平行); 1:规范相交; 2:非规范相交(重合); 3:异面不相交 
 52 int LineCross(Point a, Point b, Point c, Point d, Point &res) {
 53     // Point n = cross(b - a, d - c);
 54     Point n = dir;
 55     if ( sgn(dot( n, c - a) ) != 0) return 3;
 56     if (sgn(n.len()) == 0) {
 57         if (sgn(cross(a - b, c - b).len()) == 0) return 2;
 58         return 0;
 59     }
 60     n = d + n;
 61     Point f = cross(d - c, n - c);
 62     double t = dot(f, c - a) / dot(f, b - a);
 63     res = a + (b - a) * t;
 64     return 1;
 65 }
 66 
 67 // 线段相交判定 0:不相交; 1:规范相交; 2:非规范相交(包含端点),3:重合
 68 int SegCross(Point a, Point b, Point c, Point d,Point &res) {
 69     int k = LineCross(a, b, c, d, res);
 70     if (k == 0 || k == 3) return 0;
 71     if (k == 1) {
 72         double d1 = dot(a - res, b - res);
 73         double d2 = dot(c - res, d - res);
 74         if (d1 < -eps && d2 < -eps ) return 1;
 75         if ( (sgn(d1) == 0  && d2 < eps) || (sgn(d2) == 0 && d1 < eps) ) return 2; //包含端点
 76         return 0;
 77     }
 78     if (dot(a - c, b - c) <= 0 || dot(a - d, b - d) <= 0
 79         || dot(c - a, d - a) <= 0 || dot(c - b, d - b) <= 0)
 80         return 3;
 81     return 0;
 82 }
 83 // p1和p2是否在线段a-b的同侧,(p1,p2,a,b 同一平面)
 84 // p1,p2,a,b不同平面时,表示p1ab,p2ab两个半平面夹角是否锐角
 85 bool SameSide(Point  p1,Point p2,Point  a,Point b){
 86     return dot(cross(b - a, p1 - a), cross(b - a, p2 - a)) > -eps ;
 87 }
 88 // 点P在三角形P0, P1, P2中 (p,p0,p1,p2 同一平面)
 89 // p和p0p1,p2不同一面时,判断点p是否在p0,p1,p2形成的三角形柱形内
 90 bool PointInTri(Point P,Point  P0,Point  P1,Point  P2){
 91     return SameSide(P, P0, P1, P2) && SameSide(P, P1, P0, P2) && SameSide(P, P2, P0, P1);
 92 }
 93 bool In(Point p,Point a,Point b,Point c){
 94     if( parallel(a,b,a,c) ){
 95         return Point_on_Seg(p,a,b) || Point_on_Seg(p,a,c) || Point_on_Seg(p,b,c);
 96     }
 97     Point ta = cross(b-a,p-a);
 98     Point tb = cross(c-b,p-b);
 99     Point tc = cross(a-c,p-c);
100     return sgn(dot(ta,tb))>=0 && sgn(dot(tb,tc))>=0 && sgn(dot(ta,tc))>=0;
101 }
102 // 点在平面上的投影
103 Point point_plane_projection(Point p, Point p0, Point n) {
104     double d = dot(p - p0, n) ;
105     return p - n * d / n.len2();
106 }
107 double judge( int id){
108     if( cross(Tri[id][0]-S,T-S).len() < eps ){
109         double tmp = 0;
110         for(int i = 0;i<3;++i){
111             Point a = Tri[id][i] , b = Tri[id][(i+1)%3];
112             if( Point_on_Seg(T,a,b) ){
113                 if( Point_on_Seg(S,a,b) ) tmp = max(tmp,(S-T).len());
114                 if( Point_on_Seg(a,S,T) ) tmp = max(tmp,(a-T).len());
115                 if( Point_on_Seg(b,S,T) ) tmp = max(tmp,(b-T).len());
116             }
117             if( Point_on_Seg(a,S,T) && Point_on_Seg(b,S,T) ) return (b-a).len();
118         }
119         return tmp;
120     }
121     return 0;
122 }
123 
124 Point line_make_point(Point ua,Point ub,Point va,Point vb){
125     double t = ( (ua.x-va.x)*(va.y-vb.y)-(ua.y-va.y)*(va.x-vb.x) )
126                 / ((ua.x-ub.x)*(va.y-vb.y)-(ua.y-ub.y)*(va.x-vb.x));
127     return ua + (ub-ua)*t;
128 }
129 double solve(Point s,Point t,Point a,Point b){
130     if( !parallel(s,t,a,b) ){
131         if( !intersect(s,t,a,b) ) return 0;
132         Point tem = line_make_point(s,t,a,b);
133         return (tem-t).len();
134     }
135     if( sgn(cross(t-s,b-s).len() )!= 0 ) return 0;
136     if( Point_on_Seg(t,a,b) ){
137         double tem = 0;
138         if( Point_on_Seg(a,s,t) ) tem = max(tem,(a-t).len());
139         if( Point_on_Seg(b,s,t) ) tem = max(tem,(b-t).len());
140         return tem;
141     }
142     if( Point_on_Seg(a,s,t) && Point_on_Seg(b,s,t)) return (b-a).len();
143     return 0;
144 }
145 
146 void work(){
147     double ans = 0;
148     for(int i = 1;i<=n;++i){
149         bool Sin = In(S,Tri[i][0],Tri[i][1],Tri[i][2]);
150         bool Tin = In(T,Tri[i][0],Tri[i][1],Tri[i][2]);
151         if( Sin && Tin ){
152             ans += (T-S).len();
153             // continue;
154         }
155         if( Sin ){
156             swap(S,T);
157             swap(Sin,Tin);
158         }
159         if(vis[i]){
160             // if( Sin && Tin ) ans += (T-S).len();
161             ans += judge(i);
162             continue;
163         }    
164         else if(  Tin ){
165             if( Sin && Tin ) continue;
166             double tem = 0;
167             for(int k = 0;k<3;++k){
168                 Point a = Tri[i][k] , b = Tri[i][(k+1)%3];
169                 Point res;
170                 int tet = SegCross(a,b,S,T,res);
171                 if( tet == 1 || tet == 2){
172                     SegCross(a,b,S,T,res);
173                     tem = max(tem,(res-T).len());
174                 }
175             }
176             ans += tem;
177         }
178         else{
179             if( Sin && Tin ) continue;
180             vector<Point> res;
181             for(int k = 0;k<3;++k){
182                 Point a = Tri[i][k] , b = Tri[i][(k+1)%3];
183                 Point tem;
184                 int tet = SegCross(S,T,a,b,tem);
185                 if( tet == 1 || tet == 2) res.push_back(tem);
186             }
187             if( res.size()  ) ans += (res[1] - res[0]).len();
188         }
189     }
190     ans /= (T-S).len();
191     printf("%.8f\n",ans);
192 }
193 int main(){
194     while(~scanf("%d",&n)){
195         scanf("%lf %lf %lf",&S.x,&S.y,&S.z);
196         scanf("%lf %lf %lf",&T.x,&T.y,&T.z);
197         scanf("%lf %lf %lf",&dir.x,&dir.y,&dir.z);
198         for(int i = 1;i<=n;++i){
199             vis[i] = 0;
200             scanf("%lf %lf %lf",&Tri[i][0].x,&Tri[i][0].y,&Tri[i][0].z);
201             scanf("%lf %lf %lf",&Tri[i][1].x,&Tri[i][1].y,&Tri[i][1].z);
202             scanf("%lf %lf %lf",&Tri[i][2].x,&Tri[i][2].y,&Tri[i][2].z);
203             if( sgn( dot( cross(Tri[i][1] - Tri[i][0],Tri[i][2]-Tri[i][0]) , dir) ) == 0 ) vis[i] = 1;
204             for(int j = 0;j<3;++j){
205                 Tri[i][j] = point_plane_projection(Tri[i][j],S,dir);
206             }
207         }
208         if( sgn( cross(T-S,dir).len() ) == 0 ){
209             double ans = 0;
210             for(int i = 1;i<=n;++i){
211                 if(In(S,Tri[i][0],Tri[i][1],Tri[i][2]) ) ans = ans+1;
212             }
213             printf("%.8f\n",ans);
214             continue;
215         }
216         T = point_plane_projection(T,S,dir);
217         work();
218     }
219     return 0;
220 }
View Code

 

2020.4.23 第十二题 :codeforces1146H

题意:二维平面给你300个点,没有三点共线,问你能构造多少个五角星(不一定规则五角星)。

这题开始想了个假算法,后来就秒了。 首先五角星转换为严格凸五边形。然后dp[i] [j] [k] 代表 i 一直链接到 j 其中有 k 个线段。最后直接 sigama dp[i][i][5]即可。

我们只需要把所有线段极角排序,然后枚举每一个线段,每个线段(s,t)加进来的时候,直接把 dp[s] 转移到 dp[t] 即可。

正确性:显然,一个五边形是能够从最顶端的那条边一直转移过来的,那么会不会统计多了呢?不会!因为假如一个虚假的五边形被统计,比如说四边形加一条重边,画个图就知道是不会统计进答案的。

总结:一开始我是打算分开每个点来统计答案,但是这样有个问题就是保证不了凸性,也就是线段的斜率不保证单调,这就很难搞。而且枚举每个点的话,只能固定起点,终点没固定的话就可能会绕回来导致重边,所以我的dp一定是有两维分别是起点终点。然后我对于所有线段排序,其实就是从全局来考虑,这样问题会化简很多,判断最大最小面积三角形,以及四边形面积存在性也用到过这个思想。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define eps 1e-8
 5 const int N = 300+9;
 6 struct Point{
 7     ll x,y;
 8     int id;
 9     Point operator - (const Point& b)const{
10         return (Point){x-b.x,y-b.y};
11     }
12     double ang(){return atan2(y,x);}
13     ll cross(Point b){
14         return x*b.y - b.x*y;
15     }
16 }p[N];
17 ll dp[N][N][7];
18 struct Seg{
19     Point s,t;
20     bool operator < (const Seg& b)const{
21         double anga = (t-s).ang() , angb = (b.t-b.s).ang();
22         if( fabs(anga - angb) > eps) return anga < angb;
23         return (t-s).cross(b.t-b.s) >0;
24     }
25 }seg[N*N];
26 int main(){
27     int n;
28     int cnt = 0;
29     scanf("%d",&n);
30     for(int i = 1;i<=n;++i){
31         scanf("%lld %lld",&p[i].x,&p[i].y);
32         p[i].id = i;
33     }
34     for(int i = 1;i<=n;++i){
35         for(int j = i + 1;j<=n;++j){
36             seg[++cnt] = (Seg){p[i],p[j]};
37             seg[++cnt] = (Seg){p[j],p[i]};
38         }
39     }
40     sort(seg+1,seg+1+cnt);
41     for(int i = 1;i<=cnt;++i){
42         int tid = seg[i].t.id , sid = seg[i].s.id;
43         dp[sid][tid][1] += 1;
44         for(int j = 1;j<=n;++j){
45             for(int k = 2;k<=5;++k){
46                 dp[sid][j][k] += dp[tid][j][k-1];
47             }
48         }
49     }
50     ll ans = 0;
51     for(int i = 1;i<=n;++i) ans += dp[i][i][5];
52     printf("%lld",ans);
53 }
View Code

接下来几天先放放计几,打算训练一下图论以及cf题,提高一下个人能力。

(upd : 还是打算把cf2900以下的,题号500+的刷一波吧)

 

2020.4.24 第十三题:codeforces598F

题意:给你一个1000个点的简单多边形,给你100条直线,问你每条直线和多边形相交的部分的长度。

 

 edu1 的 F 题。。。。。

emm 思路很简单,就是对于每条直线,暴力求和简单多边形的交点,然后再统计,就是O(nm)的。 但是有一个很烦的问题就是,你怎么统计。

很容易想到射线法判断点是否在凸包里面的方法,就是每一个交点,我们就相当于 凸包内/ 凸包外 的一个状态转化,所以很容易求出来。但是有个问题就是我射线法只是判断点是不是在凸包内,所以我遇到平行线段就直接不管。但是这里不行啊!那如果平行的直接加进答案?不行!会重复,思考了一个晚上,假了一个晚上,早上起来实在没想到别的了,于是乎打了一个扫描线居然就过了。。

总体做法:先对图旋转,问题变成多边形和x轴相交线段,然后我们开一个 add 数组记录添加的线段,对于x轴上的线段直接丢进add,其他的情况也丢进add,最后add进行扫描线,这样就不会重复了。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-8
  4 const int N = 1000+9;
  5 struct Point{
  6     double x,y;
  7     Point operator - (const Point& b)const{
  8         return (Point){x-b.x,y-b.y};
  9     }
 10     Point operator * (const double& b)const{
 11         return (Point){x*b,y*b};
 12     }
 13     Point operator / (const double& b)const{
 14         return (Point){x/b,y/b};
 15     }
 16     Point turn(const double& k){
 17         return (Point){ x*cos(k)-y*sin(k),x*sin(k)+y*cos(k)};
 18     }
 19     double cross(Point a,Point b){
 20         return (a.x-x) * (b.y-y) - (b.x-x)*(a.y - y);
 21     }
 22     bool operator < (const Point& b)const{
 23         if( fabs(x-b.x) < eps ) return y < b.y;
 24         return x < b.x;
 25     }
 26     
 27 }p[N],tp[N];
 28 double X[N*3],Xadd[N*3];
 29 // struct Node{
 30 //     int num;
 31 //     double x1,x2;
 32 //     bool operator < (const Node& b)const{
 33 //         return x1 < b.x1;
 34 //     }
 35 // };
 36 int sgn(double x){
 37     if( fabs(x) < eps ) return 0;
 38     if( x < 0) return -1;
 39     return 1;
 40 }
 41 double dis(Point a,Point b){
 42     return sqrt((a.x - b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
 43 }
 44 bool insert(Point a,Point b,Point c,Point d){
 45     // cerr<<c.x<<" "<<c.y<<" "<<d.x<<" "<<d.y<<" "<<sgn(a.cross(b,d))<<" "<<a.cross(b,d)<<"!!"<<endl;
 46     // if( sgn( a.cross(b,d)) == 0 ) return 1;
 47     return sgn( a.cross(b,c) ) * sgn( a.cross(b,d) ) < 0;
 48 }
 49 Point LineCross(Point a,Point b,Point c,Point d){
 50     double u = a.cross(b,c), v = b.cross(a,d);
 51     return (Point){ (c.x*v + d.x*u)/(u+v) , (c.y*v + d.y*u)/(u+v) };
 52 }
 53 int n; 
 54 void init(){
 55     int cnt = 0;
 56     for(int i = 1;i<=n+1;++i){
 57         if( cnt>=2 && sgn(p[i].cross(tp[cnt],tp[cnt-1])) == 0 ) --cnt;
 58         tp[++cnt] = p[i];
 59     }
 60     for(int i = 1;i<=cnt;++i) p[i] = tp[i];
 61     n = cnt-1;
 62 }
 63 void solve(Point s,Point t){
 64     double deta = atan2(t.y-s.y,t.x-s.x);
 65     for(int i = 1;i<=n+1;++i){
 66         tp[i] = (p[i]-s).turn(-deta);
 67         // cerr<<i<<" "<<tp[i].x<<" "<<tp[i].y<<endl;
 68     }
 69     t = (Point){-1000000,0};
 70     s = (Point){1000000,0};
 71     int cnt = 0;
 72     // vector<Node> vec;
 73     vector< pair<double,double> > add;
 74     vector<double> tem;
 75     for(int i = 1;i<=n;++i){
 76         Point a = tp[i] , b = tp[i+1];
 77         if( fabs(a.y) < eps && fabs(b.y)<eps ){
 78             add.push_back({min(a.x,b.x) , max(a.x,b.x)});
 79             X[++cnt] = a.x; X[++cnt] = b.x;
 80             continue;
 81         }
 82         if( a.y > b.y + eps ) swap(a,b);
 83         if( fabs(b.y) < eps || ( fabs(a.y) > eps && insert(s,t,a,b) ) ){
 84             Point pt = LineCross(s,t,a,b);
 85             // cerr<<i<<" "<<tem.x<<" "<<tem.y<<endl;
 86             // tem.x1 = pt.x; tem.num = 1;
 87             // vec.push_back(tem);
 88             tem.push_back(pt.x);
 89             X[++cnt] = pt.x;
 90         }
 91     }
 92     double ans = 0;
 93     sort(X+1,X+1+cnt);
 94     cnt = unique(X+1,X+1+cnt) - X - 1;
 95     sort(tem.begin(),tem.end());
 96     for(int i = 0;i<tem.size();i+=2)  add.push_back({tem[i],tem[i+1]});
 97     for(int i = 1;i<=cnt;++i) Xadd[i] = 0;
 98     for(auto it : add){
 99         int pl = lower_bound(X+1,X+1+cnt,it.first) - X;
100         int pr = lower_bound(X+1,X+1+cnt,it.second) - X;
101         Xadd[pl] += 1; Xadd[ pr ] -= 1;
102     }
103     int num = 0;
104     for(int i = 1;i<cnt;++i){
105         num += Xadd[i];
106         if( num ) ans += X[i+1] - X[i];
107     }
108     printf("%.15f\n",ans);
109 }
110 int main(){
111     int m;
112     scanf("%d",&n);
113     scanf("%d",&m);
114     for(int i = 1;i<=n;++i) scanf("%lf %lf",&p[i].x,&p[i].y);
115     p[n+1] = p[1];
116     init();
117     for(int i = 1;i<=m;++i){
118         Point a,b; scanf("%lf %lf %lf %lf",&a.x,&a.y,&b.x,&b.y);
119         solve(a,b);
120     }
121     return 0;
122 }
123 /*
124 4 1
125 0 0
126 0 1
127 1 1
128 1 0
129 1 1 0 0
130 */
View Code

 正解:多边形线段看作有向线段,和直线向量所成正向的线段+,反向线段 - 。 其中规范相交的权值是2,交在端点上权值是1 ,和直线平行的不管。 然后再 扫描线(和我的差不多,因为交正向相当于进入多边形,交反向相当于离开多边形,处理端点,射线法是只管高点,这里是让交点是端点的权值 = 1 ,因为不规范相交不会影响,所以权值设小点就没影响了。

 1 //
 2 //  Created by TaoSama on 2016-01-19
 3 //  Copyright (c) 2015 TaoSama. All rights reserved.
 4 //
 5 #pragma comment(linker, "/STACK:1024000000,1024000000")
 6 #include <algorithm>
 7 #include <cctype>
 8 #include <cmath>
 9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12 #include <iomanip>
13 #include <iostream>
14 #include <map>
15 #include <queue>
16 #include <string>
17 #include <set>
18 #include <vector>
19 
20 using namespace std;
21 #define pr(x) cout << #x << " = " << x << "  "
22 #define prln(x) cout << #x << " = " << x << endl
23 const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
24 
25 #define double long double
26 const double EPS = 1e-8;
27 
28 int sgn(double x) {
29     return x < -EPS ? -1 : x > EPS;
30 }
31 
32 struct Point {
33     double x, y;
34     Point() {}
35     Point(double x, double y): x(x), y(y) {}
36     void read() {cin >> x >> y;}
37     Point operator-(const Point& p) {
38         return Point(x - p.x, y - p.y);
39     }
40     double operator*(const Point& p) {
41         return x * p.x + y * p.y;
42     }
43     double operator^(const Point& p) {
44         return x * p.y - y * p.x;
45     }
46     double length() {return hypotl(x, y);}
47 } poly[N];
48 
49 using Vec = Point;
50 
51 double getIntersection(Point p, Vec v, Point q, Vec w) {
52     return (w ^ (p - q)) / (v ^ w);
53 }
54 
55 int n, q;
56 
57 double gao(Point p, Vec v) {
58     double ret = 0;
59     vector<pair<double, int> > pos;
60     for(int i = 1; i <= n; ++i) {
61         int s1 = sgn(v ^ (poly[i] - p));
62         int s2 = sgn(v ^ (poly[i + 1] - p));
63         if(s1 == s2) continue; //collinear or no intersection
64         double o = getIntersection(p, v, poly[i], poly[i + 1] - poly[i]);
65         if(s1 > s2) pos.push_back({o, s1 && s2 ? 2 : 1});
66         else pos.push_back({o, s1 && s2 ? -2 : -1});
67     }
68     sort(pos.begin(), pos.end());
69     int flag = 0;
70     for(int i = 0; i + 1 < pos.size(); ++i) {
71         flag += pos[i].second;
72         if(flag) ret += pos[i + 1].first - pos[i].first;
73     }
74     return ret * v.length();
75 }
76 
77 int main() {
78 #ifdef LOCAL
79     freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
80 //  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
81 #endif
82     ios_base::sync_with_stdio(0);
83 
84     cin >> n >> q;
85     for(int i = 1; i <= n; ++i) poly[i].read();
86     poly[n + 1] = poly[1];
87     while(q--) {
88         Point A, B;
89         A.read(); B.read();
90         cout << fixed << setprecision(20) << gao(A, B - A) << '\n';
91     }
92     return 0;
93 }
View Code

 

2020.4.25 第十四题:codeforces611G

就是类似于旋转卡壳的一道题,记住多个点和一个点的叉积的和是可以变成 多个点的和的虚点 和 这个点的叉积,然后就是一个前缀和瞎搞就好了。这题很容易爆ll,然后注意面积不能取模。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 5e5+8;
 5 const ll modd = 1e9+7;
 6 struct Point{
 7     ll x,y;
 8     Point operator - (const Point& b)const{
 9         return (Point){x-b.x,y-b.y};
10     }
11 }p[N*2],all,tp[N*2];
12 ll cross(Point a,Point b){
13     return a.x*b.y - b.x*a.y;
14 }
15 ll a[N*2],sum[N*2],ssum[N*2];
16 int n; 
17 int main(){
18     scanf("%d",&n);
19     for(int i = 1;i<=n;++i) scanf("%lld %lld",&p[i].x,&p[i].y);
20     reverse(p+1,p+1+n);
21     
22     for(int i = 1;i<=n;++i) p[i+n] = p[i];
23     for(int i = 1;i<2*n;++i) a[i] = cross(p[i],p[i+1]) % modd;
24     for(int i = 1;i<2*n;++i) sum[i] = (sum[i-1] + a[i])%modd;
25     for(int i = 1;i<2*n;++i) ssum[i] = (ssum[i-1] + sum[i])%modd;
26     
27     ll tot = 0 , ans = 0;
28     all.x = 0 , all.y = 0;
29     for(int i = 1;i<=n;++i) tot += cross(p[i],p[i+1]);
30     double dtot = 1.0 * tot;
31     ll now = cross(p[1],p[2]);
32     ll cnt =0;
33     for(int l = 1,r=2;l<=n;++l){
34         
35         while( now + cross(p[r],p[r+1]) + cross(p[r+1],p[l]) < dtot/2 ){
36             now += cross(p[r],p[r+1]);
37             ++r;
38             all.x = (all.x + p[r].x + modd )%modd;
39             all.y = (all.y + p[r].y + modd )%modd;
40         }
41         ll tem = ( (ssum[r-1] - ssum[l] - (r-l-1)*sum[l-1]%modd + modd)%modd + cross(all,p[l])%modd ) % modd;
42         ans = (ans + tem) % modd;
43         all.x = (all.x - p[l+2].x + modd) % modd;
44         all.y = (all.y - p[l+2].y + modd) % modd;
45         now -= cross(p[l],p[l+1]);
46         cnt += r-l-1;
47     }
48     tot = tot % modd;
49     ans = (cnt %modd * tot % modd - 2 * ans%modd + modd) % modd;
50     printf("%lld",ans);
51     return 0;
52 }
View Code

 

2020.4.26 第十五题:codeforces958E3

分治构造题。做法:对于分治的点,找到左下角的点,扫描线找到左边的百点和黑点相同就break出来,继续分分治。 首先,假如有解,我一定可以根据这个做法构造出来的。因为假如说左边黑点链接右面百点,那么我们肯定可以重新构造来使得左边白点等于黑点,这个画画图就好了。。。。那么我这样做能找到最终解么?肯定的,因为每次这样操作一定是保证了线段不交,然后每一次操作都是一定保证线段不交,最后答案就肯定是线段不交

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 1e4+9;
 5 struct Point{
 6     int col,id;
 7     int x,y;
 8     bool operator < (const Point& b){
 9         if( x == b.x ) return y < b.y;
10         return x < b.x;
11     }
12 }p0,p[N*2];
13 int cross(Point a,Point b,Point c){
14     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
15 }
16 bool cmpang(Point a,Point b){
17     return cross(p0,a,b) > 0;
18 }
19 int ans[N];
20 void solve(int L,int R){
21     int c = L;
22     for(int i = L;i<=R;++i) if(p[i]<p[c]) c = i;
23     swap(p[c],p[L]);
24     p0 = p[L];
25     sort(p+L+1,p+R+1,cmpang);
26     int a1 = 0, a0 = 0;
27     int k = 1000000;
28     int mid = (L+R)>>1;
29     // cerr<<L<<" "<<R<<" LR"<<endl;
30     for(int i = L+1;i<= R ;++i){
31         if( a1 == a0 && p[i].col != p0.col){
32                 k = i;
33                 break;
34             // cerr<<"!!!"<<p0.id<<" "<<p[i].id<<"!!"<<endl;
35             // break;
36         }
37         if(p[i].col) ++a1;
38         else ++a0;
39     }
40     if(p0.col) ans[p[k].id] = p0.id;
41     else ans[p0.id] = p[k].id;
42     // cerr<<p0.x<<" "<<p0.y<<" "<<p[k].x<<" "<<p[k].y<<" !"<<endl;
43     // swap(p[L],p[k-1]);
44     if(L+1<k-1) solve(L+1,k-1);
45     if(k+1 < R) solve(k+1,R);
46 }
47 inline int read() {
48     char ch = getchar(); int x = 0, f = 1;
49     while(ch < '0' || ch > '9') {
50         if(ch == '-') f = -1;
51         ch = getchar();
52     } while('0' <= ch && ch <= '9') {
53         x = x * 10 + ch - '0';
54         ch = getchar();
55     } return x * f;
56 }
57 int main(){
58     
59     int n = read();
60     for(int i = 1;i<=n;++i){
61         p[i].x = read();
62         p[i].y = read();
63         p[i].col = 0; p[i].id = i;
64     }
65     for(int i = 1;i<=n;++i){
66         p[i+n].x = read();
67         p[i+n].y = read();
68         p[i+n].col = 1; p[i+n].id = i;
69     }
70     solve(1,2*n);
71     for(int i = 1;i<=n;++i) cout<<ans[i]<<"\n";
72 }
View Code

 

2020.5.6 第十六题:codeforces962G

突然发现鸽了好多天了。最近忙着作业还有其他东西,计几就停了一下。

题意:给你一个只有水平和垂直线段的简单多边形,内部染成黑色,然后给你一个矩形,问矩形内有多少个黑色区域。

做法:这题假了好多次,然后卡了一下午总算过了。其实计几有个常用的套路就是线段有向,以逆时针为方向。那么顺着这个思路想,我们可以对原来的图形建立有向线段的图。多边形和矩形交的线段在图内。矩形边上的点也在图内。然后一个黑色区域是可以从一个点dfs回自身的。所以建完图之后跑一遍dfs即可。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N = 15000+9;
  4 typedef long long ll;
  5 struct Point{
  6     int x,y;
  7     Point operator - (const Point& b)const{
  8         return (Point){x-b.x,y-b.y};
  9     }
 10 }p[N],rec[7],Gp[N];
 11 bool vis[N*5];
 12 vector< pair<int,int> > edge_pt[5];
 13 map<pair<int,int> , int > mp;
 14 vector<int> G[N];
 15 // int cross(Point a,Point b,Point c){
 16 //     return (b.x-a.x)*(c.y-b.y) - (c.x-a.x) * (a.y-b.y);
 17 // }
 18 // int dot(Point a,Point b,Point c){
 19 //     return (b.x-a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y);
 20 // }
 21 // bool onSeg(Point a,Point s,Point e){
 22 //     return cross(a,s,e)==0 && dot(a,s,e) <= 0 ;
 23 // }
 24 int n;
 25 int cnt = 0;
 26 bool judge(){
 27     double xx = (rec[1].x + rec[3].x) * 0.5;
 28     double yy = (rec[1].y + rec[3].y) * 0.5;
 29     int cnt = 0;
 30     // for(int i = 1;i<=4;++i){
 31     //     if( onSeg(,rec[i],rec[i+1])) return 1;
 32     // }
 33     for(int i = 1;i<=n;++i){
 34         if( p[i].y == p[i+1].y) continue;
 35         if( p[i].x < xx) continue;
 36         int mi = min(p[i].y,p[i+1].y) , mx = max(p[i].y,p[i+1].y);
 37         // cerr<<yy<<" "<<mi<<" "<<mx<<" !!"<<endl;
 38         if( yy <= mi || yy > mx) continue;
 39         ++cnt;
 40     }
 41     if( cnt&1 ) return 1;
 42     return cnt&1;
 43 }
 44 void add(int xa,int ya,int xb,int yb){
 45     if( !mp[{xa,ya}] ) mp[{xa,ya}] = ++cnt;
 46     if( !mp[{xb,yb}] ) mp[{xb,yb}] = ++cnt;
 47     int aid = mp[{xa,ya}], bid = mp[{xb,yb}];
 48     G[aid].push_back(bid);
 49     if( xa == rec[1].x ) edge_pt[1].push_back({ya,aid});
 50     if( xa == rec[3].x ) edge_pt[3].push_back({ya,aid});
 51     if( ya == rec[2].y ) edge_pt[2].push_back({xa,aid});
 52     if( ya == rec[4].y ) edge_pt[4].push_back({xa,aid});
 53     if( xb == rec[1].x ) edge_pt[1].push_back({yb,bid});
 54     if( xb == rec[3].x ) edge_pt[3].push_back({yb,bid});
 55     if( yb == rec[2].y ) edge_pt[2].push_back({xb,bid});
 56     if( yb == rec[4].y ) edge_pt[4].push_back({xb,bid});
 57 }
 58 void build_G(){
 59     for(int i = 1;i<=n;++i){
 60         if( p[i].x == p[i+1].x){
 61             // cerr<<i<<" "<<p[i].x<<" "<<p[i].y<<p[i+1].x<<" "<<p[i+1].y<<rec[1].x<<" "<<rec[3].x<<" !!!"<<endl;
 62             if( p[i].x <= rec[1].x || p[i].x >= rec[3].x ) continue;
 63             bool up = (p[i].y < p[i+1].y);
 64             int mx = max(p[i].y,p[i+1].y) , mi = min(p[i].y,p[i+1].y);
 65             mx = min(mx,rec[1].y) ; mi = max(mi,rec[2].y);
 66             if( mi < mx){
 67                 // cerr<<i<<" "<<mi<<" "<<mx<<"miomx"<<endl;
 68                 if(up) add(p[i].x,mi,p[i].x,mx);
 69                 else add(p[i].x,mx,p[i].x,mi);
 70             }
 71         }
 72         else{
 73             if( p[i].y >= rec[1].y || p[i].y <= rec[3].y ) continue;
 74             bool ri = (p[i].x < p[i+1].x);
 75             int mx = max(p[i].x,p[i+1].x) , mi = min(p[i].x,p[i+1].x);
 76             mx = min(mx,rec[3].x) ; mi = max(mi,rec[1].x);
 77             if( mi < mx){
 78                 if(ri) add(mi,p[i].y,mx,p[i].y);
 79                 else add(mx,p[i].y,mi,p[i].y);
 80             }
 81         }
 82     }
 83     // cerr<<cnt<<" "<<cnt<<"!"<<endl;
 84     if( cnt == 0 ){
 85         if(judge()) printf("1");
 86         else printf("0");
 87         exit(0);
 88     }
 89     for(int i = 1;i<=4;++i){
 90         if( mp[{rec[i].x,rec[i].y}]) continue;
 91         mp[{rec[i].x,rec[i].y}] = ++cnt;
 92         int x = rec[i].x , y = rec[i].y;
 93         if( x == rec[1].x ) edge_pt[1].push_back({y,cnt});
 94         if( x == rec[3].x ) edge_pt[3].push_back({y,cnt});
 95         if( y == rec[2].y ) edge_pt[2].push_back({x,cnt});
 96         if( y == rec[4].y ) edge_pt[4].push_back({x,cnt});
 97     }
 98     for(int i = 1;i<=4;++i){
 99         sort(edge_pt[i].begin(),edge_pt[i].end());
100         if( i == 1 || i == 4) reverse(edge_pt[i].begin(),edge_pt[i].end());
101         if( mp[{rec[i].x,rec[i].y}] == 0) mp[{rec[i].x,rec[i].y}] = ++cnt;
102         if( mp[{rec[i+1].x,rec[i+1].y}] == 0) mp[{rec[i+1].x,rec[i+1].y}] = ++cnt;
103         int s = mp[{rec[i].x,rec[i].y}] , e = mp[{rec[i+1].x,rec[i+1].y}];
104         for(int j = 0;j<edge_pt[i].size();++j){
105             if( j == edge_pt[i].size() - 1 && edge_pt[i][j].second != e) G[edge_pt[i][j].second].push_back(e);
106             if( j == 0 && edge_pt[i][j].second != s) G[s].push_back(edge_pt[i][j].second);
107             if( j!= edge_pt[i].size()-1) G[edge_pt[i][j].second].push_back(edge_pt[i][j+1].second);
108         }
109     }
110 }
111 bool dfs(int u,int fa){
112     // cerr<<u<<" dfsu"<<endl;
113     for(auto v : G[u]){
114         // cerr<<v<<" v"<<endl;
115         if(v == fa){
116             // cerr<<v<<" findv"<<endl;
117             return 1;
118         }
119         if( vis[v] == 0){
120             vis[v] = 1;
121             if( dfs(v,fa) ) return 1;
122         }
123     }
124     return 0;
125 }
126 int main(){
127     int x1,y1,x2,y2;
128     scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
129     rec[1] = (Point){x1,y1};
130     rec[2] = (Point){x1,y2};
131     rec[3] = (Point){x2,y2};
132     rec[4] = (Point){x2,y1};
133     rec[5] = rec[1];
134     scanf("%d",&n);
135     for(int i = 1;i<=n;++i) scanf("%d %d",&p[i].x,&p[i].y);
136     p[n+1] = p[1];
137 
138     bool cont = 1;
139     for(int i = 1;i<=n;++i){
140         if( p[i].x < rec[1].x || p[i].x > rec[3].x || p[i].y < rec[2].y || p[i].y > rec[4].y) cont = 0;
141     }
142     if( cont){
143         printf("1");
144         return 0;
145     }
146     build_G();
147     // for(auto it : mp){
148     //     cerr<<it.first.first<<" "<<it.first.second<<" "<<it.second<<"!"<<endl;
149     // }
150     int ans = 0;
151     for(int i = 1;i<=cnt;++i){
152         if(!vis[i]){
153             vis[i] = 1;
154             if(dfs(i,i)) ++ans;
155         }
156     }
157     printf("%d",ans);
158 }
159 /*
160 0 5 10 0
161 8
162 0 0
163 2 0
164 2 8
165 8 8 
166 8 0
167 10 0
168 10 10
169 0 10
170 */
View Code

 5.7(补):首先具体说说做法:就是逆时针建图,包括矩形。然后dfs的意思是,找一个点,如果能dfs回自身,说明是一个合法区域,然后不会走过经过的点。然后今天早上的时候发现做法有点假,就是假如我先从矩形顶点出发,绕矩形一圈,那么剩下的那些合法的,靠着矩形边的区域就统计不到。再比如,假如我从一个合法区域开始dfs,假如我先走矩形边,走到另一个区域,那么我自身的区域就统计不到,而且我走到的另一个区域因为打了vis标记,所以也统计不到。

然后我想了一个下午怎么修改,但是还是没有解决。然后我突然发现,其实我原来的做法的一个小细节能够把这些繁琐的问题解决,就是我建点是先建立多边形上的,再建立矩形上的,边也是一样。所以我们在遍历起点的时候,会优先遍历多边形上的,第一个问题解决了。第二个问题??一样,我们dfs优先遍历多边形上的边,也就保证我先走自身的那个区域,然后我dfs到自身就直接return,所以链接两个区域的矩形边不会被遍历到。

今天虽然没做新题,但是巩固了昨天的题。从觉得自己昨天就是个傻逼,写出这垃圾算法,怀疑cf数据,想明白之后才发现昨天自己居然写了一个神仙算法自己都没发现,哈哈哈哈哈。

 

2020.5.8 第十七题:codeforces887E

这题其实挺简单的,就是对于每个圆,二分求出不合法区域,全部求出来之后跑一遍扫描线就好了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define inf 1e12+9
 4 #define eps 1e-7
 5 struct Point{
 6     double x,y,r;
 7     Point operator + (const Point& b)const{
 8         return (Point){x+b.x,y+b.y};
 9     }
10     Point operator - (const Point& b)const{
11         return (Point){x-b.x,y-b.y};
12     }
13     Point operator * (const double& b)const{
14         return (Point){x*b,y*b};
15     }
16     Point operator / (const double& b)const{
17         return (Point){x/b,y/b};
18     }
19     double len(){ return sqrt(x*x+y*y); }
20 }p0,p1,p2,v;
21 double cross(Point a,Point b,Point c){
22     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
23 }
24 vector< pair<double,int> > vec;
25 void add(Point tem){
26     double L = -inf , R = inf;
27     double a1,a2;
28     if(cross(p1,p2,tem) > eps ) swap(L,R);
29     for(int k = 1;k<=100;++k){
30     // while(fabs(R-L) > eps){
31         double m = (L+R)/2;
32         Point pm = p0 + v * m;
33         double len = (pm-p1).len();
34         double dis = (pm-tem).len();
35         // cerr<<L<<" "<<R<<" "<<m<<" "<<dis<<" "<<tem.r<<" "<<len<<" !!"<<endl;
36         // cerr<<pm.x<<" "<<pm.y<<" xy"<<endl;
37         if( fabs(dis - tem.r) < len ) L = m;
38         else R = m;
39     }
40     // cerr<<L<<" !"<<endl;
41     a1 = L;
42 
43     L = -inf , R = inf;
44     if(cross(p1,p2,tem) > eps ) swap(L,R);
45     for(int k = 1;k<=100;++k){
46     // while( fabs(R-L) > eps){
47         double m = (L+R)/2;
48         Point pm = p0 + v * m;
49         double len = (pm-p1).len();
50         double dis = (pm-tem).len();
51         if( fabs(dis + tem.r) < len ) L = m;
52         else R = m;
53     }
54     // cerr<<L<<" !"<<endl;
55     a2 = R;
56     if( a1 > a2 ) swap(a1,a2);
57     // cerr<<a1<<" "<<a2<<" a12"<<endl;
58     vec.push_back({a1,1});
59     vec.push_back({a2,-1});
60 }
61 void solve(){
62     vec.push_back({0,0});
63     sort(vec.begin(),vec.end());
64     double ans = inf;
65     int cnt = 0;
66     for(int i = 0;i<vec.size();++i){
67         // cerr<<vec[i].first<<" "<<vec[i].second<<" "<<cnt<<" cnmt"<<endl;
68         if(cnt == 0 ) ans = min(ans,fabs(vec[i].first) );
69         cnt += vec[i].second;
70         if(cnt == 0 ) ans = min(ans,fabs(vec[i].first) );
71     }
72     // cerr<<ans<<" !"<<endl;
73     double len = (p2-p1).len() * 0.5;
74     ans = sqrt(ans*ans + len*len);
75     printf("%.10f",ans);
76     return;
77 }
78 int main(){
79     scanf("%lf %lf %lf %lf",&p1.x,&p1.y,&p2.x,&p2.y);
80     p0 = (p1+p2)*0.5;
81     v.x = -(p2-p1).y; v.y = (p2-p1).x;
82     v = v / v.len();
83     int n; scanf("%d",&n);
84     for(int i = 1;i<=n;++i){
85         Point tem; scanf("%lf %lf %lf",&tem.x,&tem.y,&tem.r);
86         add(tem);
87     }
88     solve();
89 }
90 /*
91 0 0 10 0 
92 1
93 5 2 1
94 */
View Code

 

2020.5.10 第十八题:codeforces575E

给你若干点,在这些点中选三个点,使得外接圆包含所有点,同时满足半径最大。

先求凸包,外接圆最大,肯定三个点接近比较好,所以枚举凸包连续的三个点即可。然后因为最小原覆盖的定理说明肯定能选择三个点满足外接圆包含所有点,所以肯定找得到。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll lim = 1e5;
 5 const int N = 8e5+9;
 6 struct Point{
 7     ll x,y;
 8     bool operator < (const Point& b)const{
 9         if( x == b.x ) return y < b.y;
10         return x < b.x;
11     }
12 }p[N],ch[N],ans[5];
13 int cnt = 0;
14 ll cross(Point a,Point b,Point c){
15     return (b.x-a.x) * (c.y - a.y) - (c.x - a.x) * (b.y-a.y);
16 }
17 double dist(Point a,Point b){
18     return sqrt( 1.0*(a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y-b.y) );
19 }
20 void add(Point tem,ll v){
21     if(tem.x - v >= 0 ) p[cnt++] = (Point){tem.x - v,tem.y};
22     else{
23         ll deta = v - tem.x;
24         ll ya = max((ll)0,tem.y-deta);
25         ll yb = min(lim,tem.y + deta);
26         p[cnt++] = (Point){(ll)0,ya};
27         p[cnt++] = (Point){(ll)0,yb};
28     }
29 
30     if(tem.x + v <= lim ) p[cnt++] = (Point){tem.x + v,tem.y};
31     else{
32         ll deta = v + tem.x - lim;
33         ll ya = max((ll)0,tem.y-deta);
34         ll yb = min(lim,tem.y + deta);
35         p[cnt++] = (Point){lim,ya};
36         p[cnt++] = (Point){lim,yb};
37     }
38 
39     if(tem.y - v >= 0 ) p[cnt++] = (Point){tem.x,tem.y-v};
40     else{ 
41         ll deta = v - tem.y;
42         ll xa = max((ll)0,tem.x-deta);
43         ll xb = min(lim,tem.x + deta);
44         p[cnt++] = (Point){xa,(ll)0};
45         p[cnt++] = (Point){xb,(ll)0};
46     }
47 
48     if(tem.y + v <= lim ) p[cnt++] = (Point){tem.x,tem.y+v};
49     else{ 
50         ll deta = v + tem.y - lim;
51         ll xa = max((ll)0,tem.x-deta);
52         ll xb = min(lim,tem.x + deta);
53         p[cnt++] = (Point){xa,lim};
54         p[cnt++] = (Point){xb,lim};
55     }
56 }
57 int Andrew(){
58     sort(p,p+cnt);
59     int m = 0;
60     for(int i = 0;i<cnt;++i){
61         while( m > 1 && cross( ch[m-2] , p[i], ch[m-1]) >= 0 ) --m;
62         ch[m++] = p[i];
63     }
64     int k = m;
65     for(int i = cnt-2;i>=0;--i){
66         while( m > k && cross(ch[m-2] , p[i],ch[m-1]) >= 0 ) --m;
67         ch[m++] = p[i];
68     }
69     if(cnt > 1) -- m;
70     return m;
71 }
72 double CirR(Point a,Point b,Point c){
73     double sth = 1.0 * abs( cross(a,b,c) )/( dist(a,b) * dist(a,c) ) ;
74     return dist(b,c) / sth;
75 }
76 int main(){
77     int n; scanf("%d",&n);
78     for(int i = 1;i<=n;++i){
79         ll v;
80         Point tem; scanf("%lld %lld %lld",&tem.x,&tem.y,&v);
81         add(tem,v);
82     }
83     int m = Andrew();
84     double res = 0;
85     ch[m] = ch[0]; ch[m+1] = ch[1];
86     for(int i = 0;i<m;++i){
87         if( CirR(ch[i],ch[i+1],ch[i+2]) > res){
88             res = CirR(ch[i],ch[i+1],ch[i+2]);
89             ans[0] = ch[i];
90             ans[1] = ch[i+1];
91             ans[2] = ch[i+2];
92         }
93     }
94     for(int i = 0;i<3;++i) printf("%lld %lld\n",ans[i].x,ans[i].y);
95     return 0;
96 }
View Code

 

2020.5.11 第十九题:codeforces717I  Cowboy Beblop at his computer

题意:三维空间给你两个平面环,问两个平面环是否“well-connect"(定义:不能平移,缩小旋转使得两个环分开),其实就是两个橡皮筋是否套起来。

做法: 这是我第四道三维计几。因为一个小细节wa了一发。思路挺好想的:题意已经告诉我们,只需要统计b环的线段中,从不同方向穿过a环的数量,比较数量是否相同即可。然后我们要做的就是把交点全求出来,然后两平面相交是直线,所以点都在一个直线上,然后我们求出直线和a环的交点,用排个序,用射线法就可以处理出点是否在环a内。然后统计就好了。

细节(wa点):b环线段满足什么条件才统计进入答案?统计起点不统计终点是不行的,用射线法常用方法就是统计高出线段端点,不统计线段低点即可。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N = 1e5+9;
  4 #define eps 1e-8
  5 struct Point{
  6     double x,y,z;
  7     int ty;
  8     Point operator - (const Point& b)const{
  9         return (Point){x-b.x,y-b.y,z-b.z};
 10     }
 11     Point operator + (const Point& b)const{
 12         return (Point){x+b.x,y+b.y,z+b.z};
 13     }
 14     double len(){
 15         return sqrt(x*x+y*y+z*z);
 16     }
 17     Point operator * (const double& b)const{
 18         return (Point){x*b,y*b,z*b};
 19     }
 20 }pn[N],pm[N],hn,hm,Linep[N*2];
 21 pair<double,int> num[N*2];
 22 int n,m,cnt;
 23 double dot(Point a,Point b){
 24     return a.x*b.x + a.y * b.y + a.z*b.z;
 25 }
 26 Point cross(Point a,Point b){
 27     return (Point){a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x};
 28 }
 29 //直线和平面交点
 30 Point LinePlaneIntersection(Point p1,Point p2,Point p0,Point n){
 31     Point v = p2 - p1;
 32     double t = (dot(n,p0-p1) / dot(n,p2-p1));
 33     return p1 + v*t;
 34 }
 35 Point LineCross(Point a,Point b,Point c,Point d){
 36     Point n = cross(b-a,d-c);
 37     n = d+n;
 38     Point f = cross(d-c,n-c);
 39     double t = dot(f,c-a)/dot(f,b-a);
 40     Point res = a + (b-a)*t;
 41     return res;
 42 }
 43 void solve(){
 44     cnt = 0;
 45     for(int i = 1;i<=n;++i){
 46         double nf = dot(hm,pn[i] - pm[1]);
 47         double nt = dot(hm,pn[i+1] - pm[1]);
 48         bool cro = 0;
 49         if( nf * nt < -eps ) cro = 1;
 50         else if( nf * nt < eps ){
 51             if(nf < -eps || nt < -eps ) cro = 1;
 52         }
 53         if( cro ){
 54             int tp;
 55             if(nf < -eps ) tp = 1;
 56             else tp = -1;
 57             Linep[++cnt] = LinePlaneIntersection(pn[i],pn[i+1],pm[1],hm);
 58             Linep[cnt].ty = tp;
 59         }
 60     }
 61     // cerr<<cnt<<"!"<<endl;
 62     if(cnt == 0 ){
 63         puts("NO");
 64         return;
 65     }
 66     Point lv = cross(hn,hm);
 67     for(int i = 1;i<=m;++i){
 68         Point mf = cross(lv,pm[i]-Linep[1]);
 69         Point mt = cross(lv,pm[i+1]-Linep[1]);
 70         bool cro = 0;
 71         if( dot(mf,mt) < -eps ) cro = 1;
 72         else if(dot(mf,mt) < eps){
 73             if(dot(hm,mf) > eps || dot(hm,mt) > eps ) cro = 1;
 74         }
 75         if( cro ){
 76             Linep[++cnt] = LineCross(Linep[1],Linep[1]+lv,pm[i],pm[i+1]);
 77             Linep[cnt].ty = 0;
 78         }
 79     }
 80     // cerr<<cnt<<endl;
 81     for(int i = 1;i<=cnt;++i){
 82         num[i].first = dot(Linep[i] - Linep[1],lv);
 83         num[i].second = Linep[i].ty;
 84     }
 85     sort(num+1,num+1+cnt);
 86     int a0 = 0 , a1 = 0;
 87     int now = 0;
 88     for(int i = cnt;i>=1;--i){
 89         if(num[i].second == 0 ) ++now;
 90         else if(now&1){
 91             if(num[i].second == 1) ++a1;
 92             else ++a0;
 93         }
 94     }
 95     if(a1 == a0 ) puts("NO");
 96     else puts("YES");
 97 }
 98 int main(){
 99     scanf("%d",&n);
100     for(int i = 1;i<=n;++i){
101         int xx,yy,zz; scanf("%d %d %d",&xx,&yy,&zz);
102         pn[i].x = xx; pn[i].y = yy; pn[i].z = zz;
103     }
104     scanf("%d",&m);
105     for(int i = 1;i<=m;++i){
106         int xx,yy,zz; scanf("%d %d %d",&xx,&yy,&zz);
107         pm[i].x = xx; pm[i].y = yy; pm[i].z = zz;
108     }
109     pn[n+1] = pn[1]; pm[m+1] = pm[1];
110     hn = cross(pn[2]-pn[1],pn[3]-pn[1]);
111     hm = cross(pm[2]-pm[1],pm[3]-pm[1]);
112     Point tem = cross(hn,hm);
113     if(tem.len() < eps){
114         puts("NO");
115         return 0;
116     }
117     solve();
118 }
View Code

 

2020.5.17第二十题:http://codeforces.com/group/uVAsoW2Jkj/contest/280056/attachments

这是我们的训练赛的F题。最后我没过。。。主要是对最小圆覆盖没理解透彻以及一开始想歪思路了。

题意:给你300个黑白点,求出最小半径圆包含全部黑点而不包含白点。

一开始看到300,打算直接在黑点凸包上暴力枚举三个点。但其实这个做法很假,比如两个黑点连线,一个白点很靠近连线,那么我肯定不能够只考虑这两个黑点画圆,也就是我卡这个圆不仅仅要考虑黑点,白点也要卡。那么就是最小圆覆盖了。最小圆覆盖的本质就是卡圆的边界,枚举圆上的三个点,从而来卡这个圆。可以注意到,黑点不在当前圆,那么黑点肯定在答案圆弧上,白点如果在当前圆内,那么这个白点肯定也在圆弧上,然后就是板子了。注意的是圆弧上有黑白点,如果白色点的只有一段,那么圆是合法的,因为可以向一个方向轻微挪动,多于一段则不可。

哎。。。这几天没有练计几,就没有做出计几题了。然后一个学弟做出来了。难受。。。一开始光想着怎么暴力去了。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N = 300+9;
  4 const double inf = 1e20;
  5 #define eps 1e-8
  6 struct Point{
  7     double x,y;
  8     int ty;
  9     bool operator < (const Point& b)const{
 10         return x < b.x || (x==b.x && y < b.y);
 11     }
 12     Point operator - (const Point& b)const{
 13         return (Point){x-b.x,y-b.y};
 14     }
 15     Point rotate(){
 16         return (Point){-y,x};
 17     }
 18     int len(){
 19         return sqrt(x*x+y*y);
 20     }
 21 }p[N],p0;
 22 int n,na,nb;
 23 struct Circle{
 24     Point o;
 25     double r;
 26 };
 27 int sgn(double x){
 28     if(fabs(x) < eps) return 0;
 29     if(x<0) return -1;
 30     return 1;
 31 }
 32 Point getmid(Point a,Point b){
 33     return (Point){(a.x+b.x)*0.5,(a.y+b.y)*0.5};
 34 }
 35 double cross(Point a,Point b,Point c){
 36     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
 37 }
 38 double dis(Point a,Point b){
 39     return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
 40 }
 41 int Qua(Point a){
 42     if(a.x >= 0 && a.y >= 0 ) return 1;
 43     if( a.x <= 0 && a.y >= 0 ) return 2;
 44     if(a.x <= 0 && a.y <= 0 ) return 3;
 45     return 4;
 46 }
 47 bool cmp(Point a,Point b){
 48     Point ta = a - p0;
 49     Point tb = b - p0;
 50     if( Qua(ta) == Qua(tb) ){
 51         if(cross(p0,a,b) == 0 ) return a.len() < b.len();
 52         return cross(p0,a,b) > 0;
 53     }
 54     else return Qua(ta) < Qua(tb);
 55 }
 56 Point circlein(Point a,Point b,Point c){
 57     Point v1 = b-a , v2 = a-c;
 58     v1 = v1.rotate();  v2=v2.rotate();
 59     double p1x = (a.x+b.x)*0.5 , p1y = (a.y+b.y)*0.5;
 60     double p2x = (a.x+c.x)*0.5 , p2y = (a.y+c.y)*0.5;
 61     double ux = p1x - p2x , uy = p1y - p2y;
 62     double t = (v2.x * uy - ux*v2.y)/( 1.0*v1.x*v2.y - v2.x *v1.y);
 63     double ox = p1x + v1.x*t;
 64     double oy = p1y + v1.y*t;
 65     Point res = (Point){ox,oy};
 66     return res;
 67 }
 68 bool judge(Point a,Circle ans){
 69     if(a.ty){
 70         return dis(a,ans.o) > ans.r + eps;
 71     }
 72     return dis(a,ans.o) < ans.r - eps;
 73 }
 74 void solve(){
 75     if(na==0){
 76         puts("0");
 77         return;
 78     }
 79     random_shuffle(p+1,p+1+n);
 80     Circle ans = (Circle){p[1],0};
 81     for(int i = 2;i<=n;++i){
 82         if(judge(p[i],ans)){
 83             ans = (Circle){p[i],0};
 84             for(int j = 1;j<i;++j){
 85                 if(judge(p[j],ans)){
 86                     ans.o = getmid(p[i],p[j]);
 87                     ans.r = dis(p[i],p[j])/2;
 88                     for(int k = 1;k<j;++k){
 89                         if(judge(p[k],ans)){
 90                             ans.o = circlein(p[i],p[j],p[k]);
 91                             ans.r = dis(p[i],ans.o);
 92                             cerr<<ans.o.x<<" "<<ans.o.y<<" "<<p[i].x<<" "<<p[i].y<<endl;
 93                             cerr<<ans.r<<" !!!"<<endl;
 94                         }
 95                     }
 96                 }
 97             }
 98         }
 99     }
100     if(isinf(ans.r) || isnan(ans.r)){
101         puts("The Orcs are close");
102         return;
103     }
104     vector<Point> vec;
105     for(int i = 1;i<=n;++i){
106         if(judge(p[i],ans)){
107             puts("The Orcs are close");
108             return;
109         }
110         if( sgn(dis(ans.o,p[i]) - ans.r) == 0 ) vec.push_back(p[i]);
111     }
112     p0 = ans.o;
113     sort(vec.begin(),vec.end(),cmp);
114     int has = 0;
115     for(int i = 0;i<vec.size();){
116         if(vec[i].ty == 1 ){
117             ++i;
118             continue;
119         }
120         ++has;
121         int j = i;
122         while(j+1<vec.size() && vec[j+1].ty == 0 )++j;
123         i = j+1;
124     }
125     bool ok = 0;
126     if(has<=1){
127         ok = 1;
128     }
129     else{
130         if(has>2) ok = 0;
131         else{
132             if(vec[0].ty == 0 && vec[vec.size()-1].ty == 0 ) ok = 1;
133             else ok = 0;
134         }
135     }
136     if(ok) printf("%.15f\n",ans.r);
137     else puts("The Orcs are close");
138 }
139 #define gc getchar()
140 inline int read(int &x){
141     char ch; while(!isdigit(ch = gc)) if(ch == '\n' || ch == EOF) return 0; x = ch ^ 48;
142     while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48); return 1;
143 }
144 int main(){
145     char ch;
146     while((ch = gc) != EOF){
147         n = na = nb = 0;
148         int tx,ty;
149         while(read(tx)){
150             ++n;
151             p[n].x = tx;
152             read(ty);
153             p[n].y = ty;
154             p[n].ty = 1;
155             ++na;
156         }
157         while(read(tx)){
158             ++n;
159             ++nb;
160             p[n].x = tx;
161             read(ty);
162             p[n].y = ty;
163             p[n].ty = 0;
164         }
165         solve();
166     }
167 }
View Code

 (补):下面cf549题的启发,其实这题有个更简洁好懂的做法。就是黑点的凸包肯定有至少两个点,所以最终答案肯定是在凸包的两个点或三个点上面。然后我们枚举凸包上两个点,那么最终圆心会在这中垂线上,然后我们对于其余的黑点和白点,在这个中垂线上卡线段,最终卡出来的线段即更新答案。对于那种轻微偏移的情况,其实就是卡线段的开闭区间,不用判断白点是否一段。

这样看来这题真的就是傻逼题。当时以为共线就直接圆心终点,如果早点hack这个做法,然后顺着暴力思路往下想,就会想到枚举两点,第三点卡线段。啊,太菜了。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N = 300+9;
  4 const double inf = 1e18;
  5 #define eps 1e-8
  6 struct Point{
  7     double x,y;
  8     int ty;
  9     bool operator < (const Point& b)const{
 10         return x < b.x || (x==b.x && y < b.y);
 11     }
 12     Point operator - (const Point& b)const{
 13         return (Point){x-b.x,y-b.y};
 14     }
 15     Point operator + (const Point& b)const{
 16         return (Point){x+b.x,y+b.y};
 17     }
 18     Point operator * (const double& b)const{
 19         return (Point){x*b,y*b};
 20     }
 21 }pa[N],pb[N],ch[N*2];
 22 int na,nb,m;
 23 struct Circle{
 24     Point o;
 25     double r;
 26 };
 27 int sgn(double x){
 28     if(fabs(x) < eps) return 0;
 29     if(x<0) return -1;
 30     return 1;
 31 }
 32 double cross(Point a,Point b){return a.x*b.y-b.x*a.y;}
 33 double dot(Point a,Point b){return a.x*b.x + a.y*b.y;}
 34 double len2(Point a){ return a.x*a.x + a.y*a.y;}
 35 double len(Point a){return sqrt(len2(a));}
 36 Point core(Point a,Point b,Point c){
 37     Point A=(Point){b.x-a.x,c.x-a.x}*2 , B = (Point){b.y-a.y,c.y-a.y}*2;
 38     Point C = (Point){ len2(b)-len2(a),len2(c)-len2(a) };
 39     return (Point){ cross(B,C)/cross(B,A),cross(A,C)/cross(A,B) };
 40 }
 41 int Andrew(){
 42     sort(pa,pa+na);
 43     int m = 0;
 44     for(int i = 0;i<na;++i){
 45         while( m > 1 && cross(pa[i] - ch[m-2],ch[m-1] - ch[m-2])>=0) --m;
 46         ch[m++] = pa[i];
 47     }
 48     int k = m;
 49     for(int i = na-2;i>=0;--i){
 50         while(m>k && cross(pa[i] - ch[m-2] ,ch[m-1] - ch[m-2])>=0) --m;
 51         ch[m++] = pa[i];
 52     }
 53     if(na>1) --m;
 54     return m;
 55 }
 56 double work(int f,int t){
 57     double l = -inf , r = inf;
 58     Point o = (ch[f] + ch[t])*0.5;
 59     for(int i = f+1;i<t;++i){
 60         Point c = core(ch[f],ch[t],ch[i]);
 61         double tem = len(c-o); 
 62         if( sgn(cross(ch[t] - ch[f] , c - ch[f])) > 0 ) tem = -tem;
 63         if( sgn(tem - l) > 0 ) l = tem;
 64     }
 65     for(int i = t+1;i<f+m;++i){
 66         Point c = core(ch[f],ch[t],ch[i]);
 67         double tem = len(c-o); 
 68         if( sgn(cross(ch[t] - ch[f] , c - ch[f])) > 0 ) tem = -tem;
 69         if( sgn(r - tem) > 0 ) r = tem;
 70     }
 71     if(r < l - eps) return inf;
 72     for(int i = 0;i<nb;++i){
 73         int fx = sgn(cross(ch[t] - ch[f],pb[i] - ch[f]));
 74         if(fx == 0){
 75             if( sgn( dot(ch[f] - pb[i] , ch[t] - pb[i]) ) < 0 ) return inf;
 76         }
 77         else{
 78             Point c = core(ch[f],ch[t],pb[i]);
 79             double tem = len(c-o);
 80             if( sgn(cross(ch[t] - ch[f] , c - ch[f])) > 0 ) tem = -tem;
 81             if( fx > 0 ){
 82                 tem += 2*eps;
 83                 if( sgn(tem - l) > 0 ) l = tem;
 84             }
 85             else{
 86                 tem -= 2*eps;
 87                 if( sgn(r - tem) > 0 ) r = tem;
 88             }
 89         }
 90     }
 91     if( r < l - eps ) return inf;
 92     double tem = len(ch[f]-ch[t])*0.5;
 93     if( r >-eps && l < eps) return tem;
 94     double mi = min(fabs(r),fabs(l));
 95     tem = sqrt(tem*tem + mi*mi);
 96     return tem;
 97 }
 98 void solve(){
 99     if(na <= 1){
100         puts("0");
101         return;
102     }
103     m = Andrew();
104     for(int i = 0;i<m;++i) ch[i+m] = ch[i];
105     double ans = inf;
106     for(int i = 0;i<m;++i){
107         for(int j = i+1;j<m;++j){
108             ans = min(ans,work(i,j));
109         }
110     }
111     if( ans == inf ) puts("The Orcs are close");
112     else printf("%.12f\n",ans);
113 }
114 #define gc getchar()
115 inline int read(int &x){
116     char ch; while(!isdigit(ch = gc)) if(ch == '\n' || ch == EOF) return 0; x = ch ^ 48;
117     while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48); return 1;
118 }
119 int main(){
120     char ch;
121     while((ch = gc) != EOF){
122         int tx,ty;
123         na = nb = 0;
124         while(read(tx)){
125             pa[na].x = tx;
126             read(ty);
127             pa[na].y = ty;
128             ++na;
129         }
130         while(read(tx)){
131             pb[nb].x = tx;
132             read(ty);
133             pb[nb].y = ty;
134             ++nb;
135         }
136         solve();
137     }
138 }
View Code

 

2020.5.19 第二十一题:codeforces549E

题意:给你10000黑白点,问是否有圆可以把黑白点严格分割开。

题解:这题用上一题的最小圆覆盖做法居然没过????震惊。。。

这题做法:https://blog.csdn.net/zava_1087/article/details/46447069

就是二维划为三维,然后卡三维的棱变成卡二维的棱。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define eps 1e-10
  4 #define inf 1e16
  5 const int N = 1e4+9;
  6 struct Point{
  7     double x,y;
  8     Point operator - (const Point& b)const{
  9         return (Point){x-b.x,y-b.y};
 10     }
 11     Point operator + (const Point& b)const{
 12         return (Point){x+b.x,y+b.y};
 13     }
 14     Point operator* (const double& b)const{
 15         return (Point){x*b,y*b};
 16     }
 17     bool operator < (const Point& b)const{
 18         return x < b.x || ( x==b.x && y < b.y) ;
 19     }
 20 }pa[N],pb[N],ha[N],hb[N];
 21 int na,nb,nha,nhb;
 22 vector< pair<int,int> > edge;
 23 int sgn(double x){
 24     if(fabs(x) < eps) return 0;
 25     if(x<0) return -1;
 26     return 1;
 27 }
 28 double cross(Point a,Point b){return a.x*b.y-b.x*a.y;}
 29 double dot(Point a,Point b){return a.x*b.x + a.y*b.y;}
 30 double len2(Point a){ return a.x*a.x + a.y*a.y;}
 31 double len(Point a){return sqrt(len2(a));}
 32 Point core(Point a,Point b,Point c){
 33     Point A=(Point){b.x-a.x,c.x-a.x}*2 , B = (Point){b.y-a.y,c.y-a.y}*2;
 34     Point C = (Point){ len2(b)-len2(a),len2(c)-len2(a) };
 35     return (Point){ cross(B,C)/cross(B,A),cross(A,C)/cross(A,B) };
 36 }
 37 void Andrew(Point p [],int n,Point ch[],int& m){
 38     sort(p,p+n);
 39     m = 0;
 40     for(int i = 0;i<n;++i){
 41         while( m > 1 && cross(p[i] - ch[m-2],ch[m-1] - ch[m-2])>=0) --m;
 42         ch[m++] = p[i];
 43     }
 44     int k = m;
 45     for(int i = n-2;i>=0;--i){
 46         while(m>k && cross(p[i] - ch[m-2] ,ch[m-1] - ch[m-2])>=0) --m;
 47         ch[m++] = p[i];
 48     }
 49     if(n>1) --m;
 50 }
 51 bool check(Point A[],int na,Point B[],int nb,int l,int r){
 52     if(na==1){
 53         return 1;
 54     }
 55     Point o = (A[l]+A[r])*0.5;
 56     double mi = -inf, mx = inf;
 57     int mid = -1;
 58     bool res = 1;
 59     for(int i = l+1;i<r;++i){
 60         Point c = core(A[l],A[r],A[i]);
 61         double d = len(c - o);
 62         if( sgn(cross(c-A[l],A[r]-A[l])) < 0 ) d = -d;
 63         if( mi < d  ){
 64             mi = d;
 65             mid = i;
 66         }
 67         if( mx <= mi ) res = 0;
 68     }
 69     for(int i = (r+1)%na ;i!=l;i = (i+1)%na ){
 70         Point c = core(A[l],A[r],A[i]);
 71         double d = len(c - o);
 72         if( sgn(cross(c-A[l],A[r]-A[l])) < 0 ) d = -d;
 73         if( mx > d  ) mx = d;
 74         if( mx <= mi) res = 0;
 75     }
 76     if( mx < mi + eps) res = 0;
 77     for(int i = 0;i<nb && res;++i){
 78         int fx = sgn(cross(B[i]-A[l],A[r]-A[l]));
 79         if(fx == 0){
 80             if(sgn(dot(A[r]-B[i],A[l]-B[i])) < 0 ) res = 0;
 81         }
 82         else{
 83             Point c = core(A[l],A[r],B[i]);
 84             double d = len(c-o);
 85             if( sgn(cross(c-A[l],A[r]-A[l])) < 0 ) d = -d;
 86             if(fx > 0 ){
 87                 if(mx > d  ) mx = d;
 88             }
 89             else{
 90                 if( mi < d ) mi = d;
 91             }
 92         }
 93         if( mx <= mi) res = 0;
 94     }
 95     return res || (mid!=-1 &&(check(A,na,B,nb,l,mid) || check(A,na,B,nb,mid,r)));
 96 }
 97 int main(){
 98     scanf("%d %d",&na,&nb);
 99     for(int i = 0;i<na;++i) scanf("%lf %lf",&pa[i].x,&pa[i].y);
100     for(int i = 0;i<nb;++i) scanf("%lf %lf",&pb[i].x,&pb[i].y);
101     Andrew(pa,na,ha,nha);
102     Andrew(pb,nb,hb,nhb);
103     if( check(ha,nha,pb,nb,0,nha-1) || check(hb,nhb,pa,na,0,nhb-1) ) puts("YES");
104     else puts("NO");
105     return 0;
106 }
View Code

 

2020.5.23:第二十二题:集训队训练,就一个扫描线,不写题解。

 

2020.5.29 : 第二十三题:codeforces1359F 

详见:https://i.cnblogs.com/posts/edit-done;postId=12989198

2020.6.1 第二十四题:集训队训练,就是计几+状压dp,不写了

 

2020.6.7 第二十五提:集训队训练:http://codeforces.com/group/uVAsoW2Jkj/contest/283255/problem/F

没想到咕咕咕了那么多天,因为期末了,然后很多事要做,实训实验什么的。

题意:二维平面给了你15个矩形,坐标1000以内,然后问你一条长度为L的线段最多能和多少矩形接触。

题解:首先很容易发现答案线段的一个端点一定是矩形一条边上的一个点(s点),并且某个矩形的一个端点(t点)一定在答案线段上。然后想着证明别的更好的结论,但是太菜了证明半天没证明出来,但是我们发现这个结论也足够我们ac了。因为坐标1000,所以我们可以暴力枚举矩形端点以及边上整点来统计。但是有个很重要的问题就是,有可能答案线段的s点不是整点,比如黄色线段,那么如果我们枚举s点上下的整点,会出现一种情况就是刚好统计漏了答案,也就是红蓝线段所示。

但是有一个极其重要的证明就是,即使是上述情况,我们也可以通过枚举整点来统计出答案,因为从红色线段到蓝色线段中间肯定经过绿色线段(统计漏的答案矩形的端点),也就是绿色线段,所以我们还是能通过上述方法统计答案,最后就是大暴力了。复杂度5e7,但是可以剪枝优化,所以远远达不到(甚至还没优化就擦线过了。。)

 

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long double dd;
  4 const dd eps = 1e-9;
  5 int sgn(dd x){
  6     if(fabs(x) < eps ) return 0;
  7     if(x<0) return -1;
  8     return 1;
  9 }
 10 struct Point{
 11     dd x,y;
 12     Point operator + (const Point& b)const{
 13         return (Point){x+b.x,y+b.y};
 14     }
 15     Point operator - (const Point& b)const{
 16         return (Point){x-b.x,y-b.y};
 17     }
 18     Point operator / (const double& b)const{
 19         return (Point){x/b,y/b};
 20     }
 21     Point operator * (const double& b)const{
 22         return (Point){x*b,y*b};
 23     }
 24     dd len(){return sqrt(x*x+y*y); }
 25 }p[5][16];
 26 dd cross(Point a,Point b,Point c){
 27     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
 28 }
 29 dd L;
 30 int n;
 31 
 32 //两线段是否相交
 33 bool insert(Point s1,Point t1,Point s2,Point t2,bool show = 0 ){
 34     // if(show){
 35     //     // cerr<<s1.x<<" "<<s1.y<<" s1"<<endl;
 36     //     // cerr<<t1.x<<" "<<t1.y<<" t1"<<endl;
 37     //     // cerr<<s2.x<<" "<<s2.y<<" s2"<<endl;
 38     //     // cerr<<t2.x<<" "<<t2.y<<" t2"<<endl;
 39     //     // cerr<< cross(s1,s2,t1) <<" sgn1"<<endl;
 40     //     // cerr<< cross(s1,t2,t1) <<" sgn2"<<endl;
 41     //     // cerr<< cross(s2,s1,t2) <<" sgn3"<<endl;
 42     //     // cerr<< cross(s2,t1,t2) <<" sgn"<<endl;
 43     // }
 44     return
 45         max(s1.x,t1.x) >= min(s2.x,t2.x) &&
 46         max(s2.x,t2.x) >= min(s1.x,t1.x) &&
 47         max(s1.y,t1.y) >= min(s2.y,t2.y) &&
 48         max(s2.y,t2.y) >= min(s1.y,t1.y) &&
 49         sgn( cross(s1,s2,t1) ) * sgn( cross(s1,t2,t1) )<=0 &&
 50         sgn( cross(s2,s1,t2) ) * sgn( cross(s2,t1,t2) )<=0;
 51 }
 52 int solve(Point a,Point b){
 53     // Point test = a;
 54     Point s = b;
 55     Point deta = a - b;
 56     deta = deta*L/deta.len();
 57     a = b + deta;
 58     int res = 0;
 59     for(int i = 1;i<=n;++i){
 60         bool ok = 0;
 61         for(int k = 0;k<=3 && (!ok) ;++k){
 62             if( insert(b,a,p[k][i],p[k+1][i])) ok = 1;
 63         }
 64         if(ok) ++res;
 65     }
 66     return res;
 67 }
 68 int main(){
 69     int tL;
 70     scanf("%d %d",&n,&tL);
 71     L = tL;
 72     for(int i = 1;i<=n;++i){
 73         int xa,xb,ya,yb;
 74         scanf("%d %d %d %d",&xa,&ya,&xb,&yb);
 75         p[0][i].x = xa; p[0][i].y = ya;
 76         p[1][i].x = xb; p[1][i].y = ya;
 77         p[2][i].x = xb; p[2][i].y = yb;
 78         p[3][i].x = xa; p[3][i].y = yb;
 79         p[4][i] = p[0][i];
 80     }
 81     int ans = 1;
 82     for(int i = 1;i<=n;++i){
 83         for(int k = 0;k<4;++k){
 84             for(int j = 1;j<=n;++j){
 85                 for(int x = p[0][j].x;x<=p[1][j].x;++x){
 86                     Point tem = (Point){1.0*x,p[0][j].y};
 87                     ans = max(ans,solve(p[k][i],tem));
 88                     tem.y = p[3][j].y;
 89                     ans = max(ans,solve(p[k][i],tem));
 90                 }
 91                 for(int y = p[0][j].y;y<=p[3][j].y;++y){
 92                     Point tem = (Point){p[0][j].x,1.0*y};
 93                     ans = max(ans,solve(p[k][i],tem));
 94                     tem.x = p[1][j].x;
 95                     ans = max(ans,solve(p[k][i],tem));
 96                 }
 97             }
 98         }
 99     }
100     printf("%d",ans);
101 }
View Code

 

由于搞项目,然后最近我们要选方向,我选了移动开发,所以又抽了点时间学安卓,然后又为了恢复就vp了几天,计几现在才做回来。

之前做了一道统计包含原点三角形的题,其实转换成不包含原点三角形就好了,就不贴了(25题)

 

2020.7.3第二十六题:codeforces886F

题意:给你2000个点,问你有多少条过原点的直线满足,所有点在该直线的投影点,是中心对称的。

看了看题解,知道做法就是:首先结论,如果投影中心对称,那么在该直线上这个中心对称点肯定是投影点的重心,那么反投影回去,也就是我对原来的点求个重心,那么最后投影中心肯定是重心的投影(写写柿子,用一个向量表示直线,然后投影用点积表示就知道了)

然后我们先把关于重心对称的点对删去,在剩下的点中枚举第一个点和谁对称,然后确定这条直线,然后扫一遍点判断直线符不符合即可。

这题由于担心被卡精度,所以全程用longlong,果然一切顺利哈哈哈

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N = 2e3+9;
  5 bool used[N];
  6 struct Point{
  7     ll x,y;
  8     Point operator + (const Point& b)const{
  9         return (Point){x+b.x,y+b.y};
 10     }
 11     Point operator / (const ll& b)const{
 12         return (Point){x/b,y/b};
 13     }
 14     Point operator * (const ll& b)const{
 15         return (Point){x*b,y*b};
 16     }
 17     Point rotate(){
 18         return (Point){-y,x};
 19     }
 20     bool operator < (const Point& b)const{
 21         if(x==b.x) return y < b.y;
 22         return x < b.x;
 23     }
 24     bool operator == (const Point& b)const{
 25         return x==b.x && y == b.y;
 26     }
 27     ll dot(const Point& b)const{
 28         return x*b.x + y*b.y;
 29     }
 30 }pt[N],p0;
 31 int n; 
 32 vector<Point> p;
 33 map<ll,int> mp;
 34 map<double,int> line_vis;
 35 void pre_solve(){
 36     for(int i = 1;i<=n;++i){
 37         if(used[i]) continue;
 38         for(int j = i+1;j<=n;++j){
 39             if(used[j]) continue;
 40             Point tp = (pt[i] + pt[j]);
 41             if( tp == p0 * 2){
 42                 used[i] = used[j] = 1;
 43             }
 44         }
 45     }
 46     for(int i = 1;i<=n;++i){
 47         if(used[i]) continue;
 48         p.push_back(pt[i]);
 49     }
 50 }
 51 bool judge(Point line){
 52     mp.clear();
 53     ll p0_d = p0.dot(line);
 54     for(auto v : p){
 55         ll d = v.dot(line);
 56         d -= p0_d;
 57         mp[ d ]++;
 58     }
 59     for(auto it : mp){
 60         ll val = it.first;
 61         int num = it.second;
 62         if(val == 0  ) continue;
 63         if(mp[-val] != num) return 0;
 64     }
 65     return 1;
 66 }
 67 int main(){
 68     scanf("%d",&n);
 69     for(int i = 1;i<=n;++i){
 70         scanf("%lld %lld",&pt[i].x,&pt[i].y);
 71         pt[i] = pt[i] * n;
 72         p0 = p0 + pt[i];
 73     }
 74     if(n<=2){
 75         puts("-1");
 76         return 0;
 77     }
 78     p0 = p0 / n;
 79     pre_solve();
 80     if( p.size() == 0 ){
 81         puts("-1");
 82         return 0;
 83     }
 84     int ans= 0;
 85     for(int i = 0;i<p.size();++i){
 86         double tx = (p[0].x + p[i].x)*0.5;
 87         double ty = (p[0].y + p[i].y)*0.5;
 88         tx = p0.x - tx; ty = p0.y - ty;
 89         ll temx = 2*tx , temy = 2*ty;
 90         if(temy < 0 || (temy==0 && temx < 0)){
 91             temx = -temx;
 92             temy = -temy;
 93         }
 94         Point vec = (Point){temx,temy};
 95 
 96         double the = atan2(temy,temx);
 97         if(line_vis[the]) continue;
 98         line_vis[the] = 1;
 99         vec = vec.rotate();
100         if(judge(vec)){
101             ++ans;
102             // cerr<<vec.x<<" "<<vec.y<<" vec"<<endl;
103         }
104     }
105     printf("%d",ans);
106     return 0;
107 }
View Code

 

2020.7.14 第二十七题:https://ac.nowcoder.com/acm/contest/5667/B

牛客多校第二场b题。。问所有过原点的圆中,给定点在其边上最多是多少。第一反应圆的反演,反演成直线,然后判断一条不过原点直线最多多少点在其上,结果。。反演后精度跪了,也就是判断反演后的点是不是在同一直线上精度误差不行,所以我们不应该判断是不是在同一直线上,而是通过反演图形,判断正形是不是在同一圆上来判断反演图形是不是统一直线上。(好像可以不用圆的反演做,可以根据圆的一些性质,比如中垂线,同一圆弧对角相同。。但是我第一反应就是定点圆。。圆的反演。。思路上秒杀。。)

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-6
#define ld  double
const int N = 2e3+9;
int n,ans;
vector<int> maybe;
struct Point{
    ld x,y;
    int id;
    Point operator - (const Point& b)const{
        return (Point){x-b.x,y-b.y};
    }
    Point operator + (const Point& b)const{
        return (Point){x+b.x,y+b.y};
    }
    Point operator * (ld b){
        return (Point){b*x,y*b};
    }
    ld len(){
        return sqrt(x*x + y*y);
    }
    ld len2(){
        return x*x + y*y;
    }
}pt[N],p[N];
struct Circle{
    Point o;
    ld r;
};
ld cross(Point a, Point b){
    return a.x*b.y - b.x*a.y;
}
ld dot(Point a,Point b){
    return a.x*b.x + a.y*b.y;
}
ld dis(Point a,Point b){
    return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
ld dis2(Point a,Point b){
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
   
int Quadrant(Point a)
{
    if(a.x>=0&&a.y>=0)  return 1;
    if(a.x<=0&&a.y>=0)  return 2;
    if(a.x<=0&&a.y<=0)  return 3;
    return 4;
}
bool cmp(Point a,Point b)  //先按象限从小到大排序 再按极角从小到大排序
{
    if(Quadrant(a)==Quadrant(b)){
        if( fabs( cross(a,b) ) < eps ) return a.len() < b.len();
        return cross(a,b) > 0;
    }
    else return Quadrant(a)<Quadrant(b);
}
Point Point_Inver(Circle c0,Point P){
    Point OP = P - c0.o;
    ld len = dis2(c0.o,P);
    return c0.o + OP*( c0.r * c0.r / len );
}
  
Point core(Point a,Point b,Point c){
    Point A=(Point){b.x-a.x,c.x-a.x}*2 , B = (Point){b.y-a.y,c.y-a.y}*2;
    Point C = (Point){ b.len2()-a.len2(),c.len2()-a.len2() };
    return (Point){ cross(B,C)/cross(B,A),cross(A,C)/cross(A,B) };
}
bool incir(Point o,double r,Point a){
    double d = dis(o,a);
    if(fabs(d-r) < eps ) return 1;
    return 0;
}
  
void solve(){
    if(n==1){
        ans = 1;
        return;
    }
    ans = 1;
    Point p0 = (Point){0,0};
    for(int i = 1;i<=n;++i){
        vector<Point> tem;
        for(int j = 1;j<=n;++j){
            if(j==i) continue;
            Point t = p[j] - p[i];
            t.id = p[j].id;
            tem.push_back(t);
        }
        sort(tem.begin(),tem.end(),cmp);
        for(int k = 0; k < tem.size();){
            // printf("%.12f\n", fabs(cross(p0,tem[k])) );
            if(  cross(pt[p[i].id] , pt[tem[k].id]) == 0 ){
                ++k;
                continue;
            }
            Point o = core(p0,pt[ p[i].id ] ,  pt[ tem[k].id ]);
            double r = o.len();
            int j = k;
            while( j + 1 < tem.size() &&  incir(o,r,pt[ tem[j+1].id ]) ){
                ++j;
            }
            ans = max(ans,j - k + 2);
            k = j + 1;
        }
    }
    // printf("%d",ans);
}
int main(){
    scanf("%d",&n);
    Circle c0;
    c0.o = (Point){0,0};
    c0.r = 200;
    for(int i =1;i<=n;++i){
        int x,y; scanf("%d %d",&x,&y);
        // scanf("%Lf %Lf",&pt[i].x,&pt[i].y);
        pt[i].x = x , pt[i].y = y;
        p[i] = Point_Inver(c0,pt[i]);
        p[i].id = i;
        // cerr<<i<<" "<<p[i].x<<" "<<p[i].y<<endl;
        // printf("%d %.12lf %.12lf\n",i,p[i].x,p[i].y);
    }
    solve();
    printf("%d",ans);
    // for(int i = 1;i<=n;++i) cerr<<p[i].x<<" "<<p[i].y<<" !"<<endl;
}
View Code

 

2020.7.14 第二十八题:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=893&pid=1001

给你两类点A,B类点,都是500个,问你用最少能用多少的A点包住B点。

一直以为是什么维护凸包。结果发现,枚举A中两点,假如B的点都在A左侧,那么则连一条有向边,最后就是变成图论,floyd求最小环

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int N = 500+9;
struct Point{
    int x,y;
}pn[N],pm[N];
int cross(Point a,Point b,Point c){
    return (b.x-a.x) * (c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}
int dot(Point a,Point b,Point c){
    return (b.x-a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y);
}
int dis[N][N];
int n,m; 
bool onSeg(Point a,Point b,Point c){
    return dot(c,a,b) <= 0;
}
bool judge(int x,int y){
    for(int i = 1;i<=n;++i){
        if( cross(pm[x],pm[y],pn[i]) > 0 || cross(pm[x],pm[y],pn[i]) == 0 && onSeg(pm[x],pm[y],pn[i]) ) continue;
        return 0;
    }
    return 1;
}
void solve(){
    for(int k = 1;k<=m;++k){
        for(int i = 1;i<=m;++i){
            for(int j = 1;j<=m;++j){
                dis[i][j] = min(dis[i][j] , dis[i][k] + dis[k][j]);
            }
        }
    }
    int mi = inf;
    for(int i = 1;i<=m;++i) mi = min(mi,dis[i][i]);
    if( mi == inf ){
        puts("ToT");
    }
    else printf("%d\n",m-mi);
}
int main(){
    while(~scanf("%d",&n)){
        for(int i = 1;i<=n;++i) scanf("%d %d",&pn[i].x,&pn[i].y);
        scanf("%d",&m);
        for(int i = 1;i<=m;++i) scanf("%d %d",&pm[i].x,&pm[i].y);
        for(int i = 1;i<=m;++i) for(int j = 1;j<=m;++j) dis[i][j] = inf;
        for(int i = 1;i<=m;++i){
            for(int j = 1;j<=m;++j){
                if( j == i ) continue;
                if(judge(i,j)) dis[i][j] = 1;
            }
        }
        solve();
    }
}
View Code

 

posted @ 2020-04-06 15:40  小布鞋  阅读(1089)  评论(0编辑  收藏  举报