計算幾何作業(上)

好多HDU的題,我想死。

HDU 6325 Problem G. Interstellar Travel

求從左到右字典序最小上凸殼,注意這個題不能選多個重點。
AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 200005
#define LL long long
#define Ct const
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int n;

#define Pt Point
struct Pt{
	LL x,y;
	Pt(Ct LL &x=0,Ct LL &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x + B.x , y + B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x - B.x , y - B.y); }
	LL operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
}P[maxn];
int c[maxn];
bool cmp(const int &u,const int &v){ return P[u].x == P[v].x ? P[u].y > P[v].y : P[u].x < P[v].x; }
int q[maxn],R;

int main(){
	int T;
	for(scanf("%d",&T);T--;){
		scanf("%d",&n);
		rep(i,1,n) scanf("%lld%lld",&P[i].x,&P[i].y),c[i]=i;
		stable_sort(c+1,c+1+n,cmp);
		q[R=0] = 1; 
		rep(i,2,n){
			int u=c[i];
			if(P[u].x == P[c[i-1]].x && P[u].y == P[c[i-1]].y) 
				continue;
			for(;R>=1 && (
				(P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) > 0 
				||
				((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) == 0 && u < q[R]) 
				)
				;)
				R--;
			q[++R] = u;
		}
		rep(i,0,R) printf("%d%c",q[i]," \n"[i==R]);
	}
}

HDU 2202 最大三角形

nn個點中選三個點的最大三角形面積。
首先存在一個最大三角形三個點都在凸包上。
求出凸包後有O(n2)O(n^2)的旋轉卡殼和O(n3)O(n^3)的暴力枚舉算法。
但是他們都能過。
這是因爲這道題有一個性質是x,yN1e4x,y1e4x,y \in \N \wedge -1e4 \leq x , y \leq 1e4
C=1e4C = 1e4
有一個結論就是凸包上的點數上界是O(C23)O(C^\frac 23)(期望點數是O(logC)O(\log C)的)
首先很多構造凸包的想法都是O(C12)O(C^\frac 12)的,
證明思路應該是有效的斜率只有O(C23)O(C^\frac 23)種(具體證明應該和SternBrocot TreeStern-Brocot\ Tree有關,也就是和最簡分數有關其實就是我不會),這是答案的上界。
然後這裏給出一個構造:
造一個x2+y2C2x^2 + y^2 \leq C^2的圓,把圓內所有頂點造個凸包,容易發現這個凸包的點數就是O(n23)O(n ^ \frac 23)級別的。
這東西怎麼網上一點提示都沒有啊啊啊啊啊啊啊啊啊連CF出題人都敷衍了事這莫非是什麼離譜的openproblem嗎

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 50005
#define LL long long
#define Ct const
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int n;

#define Pt Point
struct Pt{
	LL x,y;
	Pt(Ct LL &x=0,Ct LL &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x + B.x , y + B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x - B.x , y - B.y); }
	LL operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
}P[maxn];
int c[maxn];
bool cmp(const int &u,const int &v){ return P[u].x == P[v].x ? P[u].y > P[v].y : P[u].x < P[v].x; }
int q[maxn],R;

int main(){
	//freopen("1.in","r",stdin);
	for(;scanf("%d",&n) != EOF;){
		rep(i,1,n) scanf("%lld%lld",&P[i].x,&P[i].y),c[i]=i;
		stable_sort(c+1,c+1+n,cmp);
		q[R=0] = c[1]; 
		rep(i,2,n){
			int u=c[i];
			for(;R>=1 && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
			q[++R] = u;
		}
		int L = R;
		per(i,n,1){
			int u = c[i];
			for(;R>L && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
			q[++R] = u;
		}
		LL ans = 0;
		rep(i,0,R) rep(j,i+1,R) rep(k,j+1,R)
			ans = max(ans , abs((P[q[j]]-P[q[i]]) * (P[q[k]]-P[q[i]])));
		printf("%.2lf\n",(double)ans / 2);
	}
}

HDU 1392 Surround the Trees

垃圾題目,題意有病,建議出題人審視一下自己的conscience
AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 50005
#define LL long long
#define Ct const
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int n;
double sqr(double a){ return a * a; }
#define Pt Point
struct Pt{
    LL x,y;
    Pt(Ct LL &x=0,Ct LL &y=0):x(x),y(y){}
    Pt operator +(Ct Pt &B)Ct{ return Pt(x + B.x , y + B.y); }
    Pt operator -(Ct Pt &B)Ct{ return Pt(x - B.x , y - B.y); }
    LL operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
    double dist(Ct Pt &B)Ct{
        return sqrt(sqr(x - B.x) + sqr(y - B.y));
    }
}P[maxn];
int c[maxn];
bool cmp(const int &u,const int &v){ return P[u].x == P[v].x ? P[u].y > P[v].y : P[u].x < P[v].x; }
int q[maxn],R;

int main(){
    //freopen("1.in","r",stdin);
    for(;scanf("%d",&n) != EOF && n;){
        rep(i,1,n) scanf("%lld%lld",&P[i].x,&P[i].y),c[i]=i;
        stable_sort(c+1,c+1+n,cmp);
        q[R=0] = c[1]; 
        rep(i,2,n){
            int u=c[i];
            for(;R>=1 && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
            q[++R] = u;
        }
        int L = R;
        per(i,n,1){
            int u = c[i];
            for(;R>L && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
            q[++R] = u;
        }
        double ans = 0;
        rep(i,0,R-1) ans += P[q[i]].dist(P[q[i+1]]);
        if(n == 2) ans /= 2;
        printf("%.2lf\n",ans);
    }
}

HDU 1469 Video Surveillance

求多邊形的核。
注意到Thus the edges alternate between horizontal and vertical.
所以爲什麼要寫半平面交呢?

AC Code\mathcal AC \ Code

#include<cstdio>
#include<algorithm>
#define maxn 105
#define inf 0x3f3f3f3f
using namespace std;

int n,x[maxn],y[maxn],mnx,mxx,mny,mxy;

int main(){
	int cas = 0;
	while(~scanf("%d",&n) && n){
		for(int i=0;i<n;i++) scanf("%d%d",&x[i],&y[i]);
		mnx = mny = -inf;
		mxx = mxy = inf;
		for(int i=0;i<n;i++){
			int v = (i+1)%n;
			if(x[i] == x[v]){
				if(y[i] > y[v]) mxx = min(mxx , x[i]);
				else mnx = max(mnx , x[i]);
			}
			else{
				if(x[i] < x[v]) mxy = min(mxy , y[i]);
				else mny = max(mny , y[i]);
			}
		}
		printf("Floor #%d\n",++cas);
		if(mnx > mxx || mny > mxy) puts("Surveillance is impossible.");
		else puts("Surveillance is possible.");
		putchar('\n');
	}
}

HDU 5462 Manors

nn個人,每個人有mm個旗子座標爲xi,j,yi,jx_{i,j},y_{i,j},求在409524095^2 的土地上每一個點x,yx,y按照fi(x,y)f_i(x,y)計算的最小的那個ii就是這個位置的主人,求每個人的土地大小。

fi(x,y)=mx2+my22xjxi,j2yjyi,j+jxi,j2+yi,j2f_i(x,y) = mx^2+my^2-2x\sum_{j}x_{i,j}-2y\sum_{j}y_{i,j}+\sum_{j}x_{i,j}^2+y_{i,j}^2

fi(x,y)fk(x,y)=2j(xi,jxk,j)x2j(yi,jyk,j)y+j(xi,j2+yi,j2xk,j2yk,j2)0f_i(x,y) - f_k(x,y) = -2\sum_{j}(x_{i,j} - x_{k,j})x -2\sum_{j}(y_{i,j}-y_{k,j})y+\sum_{j}(x_{i,j}^2+y_{i,j}^2-x_{k,j}^2-y_{k,j}^2) \leq 0
半平面交即可得到面積。

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define db double
#define Ct const
#define Pt Point
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define eps 1e-8
#define maxn 205
#define maxm 2005
using namespace std;

int n,m;
db x[maxn][maxm] , y[maxn][maxm] , smx[maxn] , smy[maxn] , smx2[maxn] , smy2[maxn];

int dcmp(Ct db &a){ return a < -eps ? -1 : a > eps ? 1 : 0; }
db sqr(Ct db &a){ return a * a; }
struct Pt{
	db x,y;
	Pt(Ct db &x=0,Ct db &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x+B.x,y+B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x-B.x,y-B.y); }
	db operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
	Pt operator *(Ct db &B)Ct{ return Pt(x * B , y * B); }
}qp[maxn];
struct Ln{
	Pt S,T;
	db ang;
	Ln(Ct Pt &S=0,Ct Pt &T=0):S(S),T(T){ ang = atan2(T.y-S.y,T.x-S.x); }
	bool operator <(Ct Ln &B)Ct{ return dcmp(ang - B.ang) ? ang < B.ang : (B.T - S) * (T - S) < 0; }
}L[maxn],q[maxn];
int cnt,ql,qr;

Pt Itp(Ct Pt &p1,Ct Pt &v1,Ct Pt &p2,Ct Pt &v2){ return p1 + v1 * ((p2 - p1) * v2 / (v1 * v2)); }
#define Ptln(a) a.S,a.T-a.S

db HalfPlaneInsection(){
	sort(L+1,L+1+cnt);
	ql=0,qr=-1;
	rep(i,1,cnt) if(i == 1 || dcmp(L[i].ang - L[i-1].ang)){
		for(;ql<=qr-1 && (qp[qr] - L[i].S) * (L[i].T - L[i].S) <= 0;qr--);
		for(;ql<=qr-1 && (qp[ql+1] - L[i].S) * (L[i].T - L[i].S) <= 0;ql++);
		q[++qr] = L[i];
		if(ql<=qr-1) qp[qr] = Itp(Ptln(q[qr]),Ptln(q[qr-1]));
	}
	for(;ql<=qr-2 && (qp[qr] - q[ql].S) * (q[ql].T - q[ql].S) <= 0;qr--);
	if(qr-ql<2) return 0;
	qp[ql] = Itp(Ptln(q[qr]),Ptln(q[ql]));
	db ans = 0;
	rep(i,ql,qr){
		int v = i + 1;
		if(v > qr) v = ql;
		ans += (qp[i] - qp[ql]) * (qp[v] - qp[ql]); 
	}
	return ans / 2;
}

int main(){
	int T,cas=0;
	for(scanf("%d",&T);T--;){
		scanf("%d%d",&n,&m);
		rep(i,1,n) smx[i] = smy[i] = smx2[i] = smy2[i] = 0;
		rep(i,1,n) rep(j,1,m) scanf("%lf%lf",&x[i][j],&y[i][j]) , smx[i] += x[i][j] , smx2[i] += sqr(x[i][j]) , smy[i] += y[i][j] , smy2[i] += sqr(y[i][j]);
		printf("Case #%d: ",++cas);
		rep(i,1,n){
			cnt = 0;
			rep(j,1,n) if(i^j){
				db A=2 * (smx[j] - smx[i]),B=2 * (smy[j] - smy[i]),C=smx2[i] + smy2[i] - smx2[j] - smy2[j];
				Pt S , T;
				if(dcmp(A)) S = Pt(- C / A , 0);
				else S = Pt(0 , -C / B);
				T = S + Pt(B,-A);
				L[++cnt] = Ln(S,T);
			}
			L[++cnt] = Ln(Pt(0,0) , Pt(0,4095));
			L[++cnt] = Ln(Pt(0,4095) , Pt(4095,4095));
			L[++cnt] = Ln(Pt(4095,4095),Pt(4095,0));
			L[++cnt] = Ln(Pt(4095,0),Pt(0,0));
			printf("%d%c",(int)round(HalfPlaneInsection())," \n"[i==n]);
		}
	}
}

HDU 4327 Shooting

[0,1]×[0,1][0,1]\times [0,1]的平面內每個點(x,y)(x,y)有個權重f(x,y)=2xyf(x,y) = 2 - x - y,平面內有nn個點{pi}\{p_i\},現在在平面上帶權隨機選擇一個點,問離這個點最近的點是pip_i的概率。

和上題基本一樣,半平面交求出每個點的範圍後求積分:
假如是S(a,b),T(c,d)S(a,b),T(c,d),求線段STS\rightarrow T下的帶權積分。
x=aby=0c+(dc)(xa)ba2xydxdy\int_{x=a}^b \int_{y=0}^{c + \frac {(d-c)(x-a)}{b-a}} 2-x-y{\rm d}x{\rm d}y
形式不太優美,設y=kx+By = kx + B
原式分成三部分:
x=aby=0kx+B2=(ba)(d+c)\int_{x=a}^b \int_{y=0}^{kx+B} 2 = (b-a)(d+c)
x=abxy=0kx+B1=x=abkx2Bx=k(a3b3)3+(a2b2)B2\int_{x=a}^b -x \int_{y=0}^{kx+B} 1=\int_{x=a}^b -kx^2-Bx = \frac {k(a^3-b^3)}3 + \frac{(a^2-b^2)B}2
x=aby=0kx+By=x=abk2x2+B22+kBx=k2(a3b3)6+B2(ab)2+kB(a2b2)2-\int_{x=a}^b\int_{y=0}^{kx+B} y = -\int_{x=a}^b \frac {k^2x^2+B^2}2+kBx = \frac {k^2(a^3-b^3)}6+\frac {B^2(a-b)}2 + \frac {kB(a^2-b^2)}2
然後就硬算即可。

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define db double
#define Ct const
#define Pt Point
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define eps 1e-8
#define maxn 205
#define maxm 2005
using namespace std;

int n,m;
db x[maxn],y[maxn];

int dcmp(Ct db &a){ return a < -eps ? -1 : a > eps ? 1 : 0; }
db sqr(Ct db &a){ return a * a; }
db cube(Ct db &a){ return a * a * a; }
struct Pt{
	db x,y;
	Pt(Ct db &x=0,Ct db &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x+B.x,y+B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x-B.x,y-B.y); }
	db operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
	Pt operator *(Ct db &B)Ct{ return Pt(x * B , y * B); }
}qp[maxn];
struct Ln{
	Pt S,T;
	db ang;
	Ln(Ct Pt &S=0,Ct Pt &T=0):S(S),T(T){ ang = atan2(T.y-S.y,T.x-S.x); }
	bool operator <(Ct Ln &B)Ct{ return dcmp(ang - B.ang) ? ang < B.ang : (B.T - S) * (T - S) < 0; }
}L[maxn],q[maxn];
int cnt,ql,qr;

Pt Itp(Ct Pt &p1,Ct Pt &v1,Ct Pt &p2,Ct Pt &v2){ return p1 + v1 * ((p2 - p1) * v2 / (v1 * v2)); }
#define Ptln(a) a.S,a.T-a.S

db HalfPlaneInsection(){
	sort(L+1,L+1+cnt);
	ql=0,qr=-1;
	rep(i,1,cnt) if(i == 1 || dcmp(L[i].ang - L[i-1].ang)){
		for(;ql<=qr-1 && (qp[qr] - L[i].S) * (L[i].T - L[i].S) <= 0;qr--);
		for(;ql<=qr-1 && (qp[ql+1] - L[i].S) * (L[i].T - L[i].S) <= 0;ql++);
		q[++qr] = L[i];
		if(ql<=qr-1) qp[qr] = Itp(Ptln(q[qr]),Ptln(q[qr-1]));
	}
	for(;ql<=qr-2 && (qp[qr] - q[ql].S) * (q[ql].T - q[ql].S) <= 0;qr--);
	if(qr-ql<2) return 0;
	qp[ql] = Itp(Ptln(q[qr]),Ptln(q[ql]));
	db ans = 0;
	rep(i,ql,qr){
		int v = i + 1;
		if(v > qr) v = ql;
		if(dcmp(qp[i].x - qp[v].x)){
			db K = (qp[v].y - qp[i].y) / (qp[v].x - qp[i].x) , B = qp[i].y - qp[i].x * K;
			ans += (qp[v].x - qp[i].x) * (qp[v].y + qp[i].y)
				+ K * (cube(qp[i].x) - cube(qp[v].x)) / 3 
				+ B * (sqr(qp[i].x) - sqr(qp[v].x)) / 2
				+ sqr(K) * (cube(qp[i].x) - cube(qp[v].x)) / 6
				+ sqr(B) * (qp[i].x - qp[v].x) / 2
				+ K * B * (sqr(qp[i].x) - sqr(qp[v].x)) / 2;
		}
	}
	return fabs(ans);
}

int main(){
	int T,cas=0;
	for(scanf("%d",&T);T--;){
		scanf("%d",&n);
		rep(i,1,n) scanf("%lf%lf",&x[i],&y[i]);
		printf("Case #%d:\n",++cas);
		rep(i,1,n){
			cnt = 0;
			rep(j,1,n) if(i^j){
				db A=2 * (x[j] - x[i]),B=2 * (y[j] - y[i]),C=sqr(x[i]) + sqr(y[i]) - sqr(x[j]) - sqr(y[j]);
				Pt S , T;
				if(dcmp(A)) S = Pt(- C / A , 0);
				else S = Pt(0 , -C / B);
				T = S + Pt(B,-A);
				L[++cnt] = Ln(S,T);
			}
			L[++cnt] = Ln(Pt(0,0) , Pt(0,1));
			L[++cnt] = Ln(Pt(0,1) , Pt(1,1));
			L[++cnt] = Ln(Pt(1,1),Pt(1,0));
			L[++cnt] = Ln(Pt(1,0),Pt(0,0));
			printf("%.6lf\n",HalfPlaneInsection());
		}
	}
} 	

HDU 6354 Everything Has Changed

用一堆圓來切割一個圓心爲原點,半徑爲R的圓A,問切割完畢後圓A外圍剩餘部分的周長。

注意到題目中所有圓都只會和大圓AA相交,所以直接判斷相交後加入大圓被刪去的部分加回小圓加入的部分。

CodeCode

#include<bits/stdc++.h>
#define db double
#define Pi 3.1415926535897932384626433832795
using namespace std;

int m;
db R,x,y,r;
db sqr(db a){ return a * a; }

int main(){
	int T;
	scanf("%d",&T);
	for(;T--;){
		scanf("%d%lf",&m,&R);
		db ans = 2 * Pi * R;
		for(int i=1;i<=m;i++){
			scanf("%lf%lf%lf",&x,&y,&r);
			db d = sqrt(x*x+y*y);
			if(d + r >= R && d - r <= R){
				db a = acos((sqr(d) + sqr(R) - sqr(r)) / d / 2 / R);
				db b = acos((sqr(d) + sqr(r) - sqr(R)) / d / 2 / r);
				ans += b * 2 * r - a * 2 * R;
			}
		}
		printf("%.15lf\n",ans);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章