日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

POJ 计算几何

發(fā)布時間:2025/5/22 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ 计算几何 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

計(jì)算幾何學(xué)

幾何公式

poj1265(pick定理)

叉積和點(diǎn)積的運(yùn)用

poj2031,poj1039

多邊型的簡單算法和相關(guān)判定

poj1408,poj1584

凸包

poj2187,poj1113

?

?

?

?

?

?

?

?POJ 1265

這題貌似。。。pick定理+線段上的整數(shù)點(diǎn)的個數(shù)+叉積求多邊形面積。。。

pick定理:http://www.cnblogs.com/vongang/archive/2012/04/07/2435741.html

線段上的整數(shù)點(diǎn)的個數(shù):算導(dǎo)上的推論,方程ax ≡ c (mod b)或者對模n有d個不同的解,或則無解。 同余方程可寫成 ax + by = c. 即是線段ab上有d個整數(shù)點(diǎn)。

叉積求多邊形面積:明白叉積的概念就很清楚了,設(shè)叉積 A = p0p1 × p0p2 。|A|表示平行平行四邊形p0p1p0'p2的面積。如果A < 0 表示p1 在p2 的逆時針方向上。以某一個點(diǎn)為p0,則所求的多邊形的面積就是沿順時針方向兩兩相鄰的所有叉積和。(網(wǎng)上有很多證明。)

View Code #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

const int MAXN = 110;

struct pot {
int x;
int y;
pot(int a = 0, int b = 0) : x(a), y(b) {}
pot operator + (const pot b) {
return pot(x + b.x, y + b.y);
}
}p[MAXN];

int det(pot a, pot b) {
return a.x * b.y - a.y * b.x;
}

int gcd(int a, int b) {
if(b == 0) return a;
return gcd(b, a % b);
}

int main() {
//freopen("data.in", "r", stdin);

int T, n, i, B, I, cas = 0;
double area;
pot u;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
p[0] = pot(0, 0);
B = I = 0;
for(i = 1; i <= n; ++i) {
scanf("%d%d", &u.x, &u.y);
B += abs(double(gcd(u.x, u.y)));
p[i] = p[i-1] + u;
}
area = 0;

for(i = 0; i <= n; ++i) {
//printf("%d %d\n", p[i].x, p[i].y);
area += det(p[i], p[i+1]);
}

area = abs(area)/2;
I = area + 1 - B/2;

printf("Scenario #%d:\n%d %d %.1lf\n", ++cas, I, B, area);
if(T) printf("\n");
}
return 0;
}


POJ 2031

這題看題目挺嚇人的,還三維坐標(biāo)系。其實(shí)就是求出各球之間的距離,然后prim求最小生成樹。幸虧有這一句?you may consider that two corridors never intersect,要不然有得惡心了。。。

渣代碼:

View Code #include <iostream> #include <cstdio> #include <cstring> #include <cmath>using namespace std;const int MAXN = 110; const double eps = 1e-8; const double inf = 30010.0;struct node {double x;double y;double z;double r; } cir[MAXN];double mp[MAXN][MAXN]; double low[MAXN]; bool vis[MAXN]; int n;double cmp(double x) {if(x > eps) return 1;else if(x < -eps) return -1;return 0; }double dis(node a, node b) {a.x -= b.x; a.y -= b.y; a.z -= b.z;double d = sqrt(a.x*a.x + a.y*a.y + a.z*a.z) - a.r - b.r;if(cmp(d) <= 0) return 0;return d; }double prim() {int i, j, f;double sum = 0, min;for(i = 0; i < n; ++i) {low[i] = mp[0][i];vis[i] = false;}low[0] = 0; vis[0] = true;for(i = 1; i < n; ++i) {min = inf; f = 0;for(j = 1; j < n; ++j) {if(!vis[j] && min > low[j]) {min = low[j]; f = j;}}if(f != 0) sum += min;vis[f] = true;for(j = 1; j < n; ++j) {if(!vis[j] && low[j] - mp[f][j] > eps) {low[j] = mp[f][j];}}}return sum; }int main() {//freopen("data.in", "r", stdin);int i, j;double d, ans;while(scanf("%d", &n), n) {for(i = 0; i < n; ++i) {for(j = 0; j < n; ++j) {if(i == j) mp[i][j] = 0;else mp[i][j] = inf;}}for(i = 0; i < n; ++i) {scanf("%lf%lf%lf%lf", &cir[i].x, &cir[i].y, &cir[i].z, &cir[i].r);for(j = 0; j < i; ++j) {d = dis(cir[j], cir[i]);mp[i][j] = mp[j][i] = d;}}ans = prim();printf("%.3lf\n", ans);}return 0; }


POJ 1039

黑書上的練習(xí)題,為了這道題我啥都沒干,看了一天多的黑書。。。=_=!?? 以下內(nèi)容摘自黑書:

?  題意:有一寬度為1的折線管道,上面頂點(diǎn)為(xi,yi),所對應(yīng)的下面頂點(diǎn)為(xi,yi-1),假設(shè)管道都是不透明的,不反射的,光線從左邊入口處的(x0,y0),(x,y0-1)之間射入,向四面八方傳播,求解光線最遠(yuǎn)能傳播到哪里(取x坐標(biāo))或者是否能穿透整個管道.
???? 如果一根光線自始至終都未擦到任何頂點(diǎn),那么它肯定不是最優(yōu)的,因?yàn)榭梢酝ㄟ^平移來使之優(yōu)化,如果只碰到一個頂點(diǎn),那也不是最優(yōu)的,可以通過旋轉(zhuǎn),使它碰到另一個頂點(diǎn),并且更優(yōu),即最優(yōu)光線一定擦到一個上頂點(diǎn)和一個下頂點(diǎn).
???? 所以可以任取一個上頂點(diǎn)和一個下頂點(diǎn),形成直線L,若L能射入左入口,即當(dāng)x=x0時,直線L在(x0,y0)和(x0,y0-1)之間,則是一條可行光線.再從左到右一次判斷每條上,下管道是否與L相交,相交則求交點(diǎn),并把交點(diǎn)x值與當(dāng)前最佳值比較,若所有管壁都不予L相交,則說明L射穿了整個管道.

然后參考莊神的模板做的,Orz。。。

渣代碼:

?

View Code #include <iostream> #include <cstdio> #include <cstring> #include <cmath>using namespace std;const int MAXN = 100; const double eps = 1e-8; const double inf = ~0u;struct point {double x;double y; };point up[MAXN], dn[MAXN]; int n;int dbcmp(double x) {if(x > eps) return 1;else if(x < -eps) return -1;return 0; }double det(double x1, double y1, double x2, double y2) {return x1*y2 - x2*y1; }double cross(point a, point b, point c) {return det(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y); }int segcross(point a, point b, point c, point d) { //判線段與直線相交,做一次跨立實(shí)驗(yàn)即可int d1, d2;d1 = dbcmp(cross(a, b, c));d2 = dbcmp(cross(a, b, d));if(d1*d2 <= 0) return true;return false; }double get_x(point a, point b, point c, point d) { //從題意可以知道,不存在與y軸平行的直線,所以可以直接用點(diǎn)斜式求交點(diǎn)double k1, k2, c1, c2;k1 = (a.y - b.y)/(a.x - b.x);k2 = (c.y - d.y)/(c.x - d.x);c1 = a.y - k1*a.x;c2 = c.y - k2*c.x;return (c2 - c1)/(k1 - k2); }double solve(point a, point b) {int i = 0;double t, ans = -inf;while(i < n && segcross(a, b, up[i], dn[i])) ++i;if(i == 0) return -inf;if(i == n) return up[n-1].x;if(segcross(a, b, up[i], up[i-1])) {t = get_x(a, b, up[i], up[i-1]);if(dbcmp(t - ans) > 0) ans = t;}if(segcross(a, b, dn[i], dn[i-1])) {t = get_x(a, b, dn[i], dn[i-1]);if(dbcmp(t - ans) > 0) ans = t;}return ans; }int main() {//freopen("data.in", "r", stdin);int i, j;bool flag;double res;while(scanf("%d", &n), n) {for(i = 0; i < n; ++i) {scanf("%lf%lf\n", &up[i].x, &up[i].y);dn[i].x = up[i].x; dn[i].y = up[i].y - 1;}res = -inf; flag = true;for(i = 0; i < n && flag; ++i) {for(j = i + 1; j < n && flag; ++j) {res = max(res, solve(up[i], dn[j]));res = max(res, solve(dn[i], up[j]));if(dbcmp(res - up[n-1].x) >= 0) flag = false;}}if(flag) printf("%.2f\n", res);else puts("Through all the pipe.");}return 0; }

?

?POJ 1408

  純屬YY題,叉積求交點(diǎn),叉積求多邊形面積。然后取最大的面積就ok了。昨天調(diào)了一晚上,還以為是叉積求交點(diǎn)出錯了呢,原來是求面積的時候算錯三角形了,唉。。。T_T

View Code #include <iostream> #include <cstdio> #include <cstring> #include <cmath>using namespace std;const int M = 50; const double eps = 1e-8; const double inf = ~0u;struct point {double x;double y;point(double a = 0, double b = 0) : x(a), y(b) {} };point a[M], b[M], c[M], d[M], p[M][M];int dbcmp(double x) {if(x > eps) return 1;else if(x < -eps) return -1;return 0; }double det(double x1, double y1, double x2, double y2) {return x1*y2 - x2*y1; }double cross(point a, point b, point c) {return det(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y); }point seg(point a, point b, point c, point d) { //叉積求交點(diǎn)double s1, s2;s1 = cross(a, b, c);s2 = cross(a, b, d);point t;t.x = (c.x*s2 - d.x*s1)/(s2 - s1);t.y = (c.y*s2 - d.y*s1)/(s2 - s1);return t; }double area(point a, point b, point c, point d) { //叉積求面積double ret = 0;ret = cross(a, b, c) + cross(a, c, d);return fabs(ret)/2.0; }void init(int n) {int i;for(i = 0; i < n; ++i) {scanf("%lf", &a[i].x);a[i].y = 0;}for(i = 0; i < n; ++i) {scanf("%lf", &b[i].x);b[i].y = 1;}for(i = 0; i < n; ++i) {scanf("%lf", &c[i].y);c[i].x = 0;}for(i = 0; i < n; ++i) {scanf("%lf", &d[i].y);d[i].x = 1;} }int main() {//freopen("data.in", "r", stdin);int n, i, j;double res = -inf, ta;point p1, p2, p3, p4;while(scanf("%d", &n), n) {init(n);res = -inf;p[0][0] = point(0, 0); p[n+1][n+1] = point(1, 1);p[0][n+1] = point(0, 1); p[n+1][0] = point(1, 0);for(i = 0; i < n; ++i) p[0][i+1] = c[i];for(i = 0; i < n; ++i) p[n+1][i+1] = d[i];for(i = 0; i < n; ++i) p[i+1][0] = a[i];for(i = 0; i < n; ++i) p[i+1][n+1] = b[i];for(i = 0; i < n; ++i) {for(j = 0; j < n; ++j) {p[i+1][j+1] = seg(a[i], b[i], c[j], d[j]);}}++n;for(i = 0; i <= n; ++i) {for(j = 0; j <= n; ++j) {if(i + 1 <= n && j + 1 <= n) {ta = area(p[i][j], p[i+1][j], p[i+1][j+1], p[i][j+1]);if(dbcmp(ta - res) > 0) res = ta;}}}printf("%.6lf\n", res);}return 0; }

?

?POJ 1584

題意:給出多邊形頂點(diǎn)的個數(shù),圓的半徑,圓的x,y坐標(biāo),并且按順時針(或逆時針)給出一個序列,表示一個多邊形,判斷這個多邊形是不是凸包。如果是,判斷圓是否在多邊形內(nèi)。。。

1、判凸包可以枚舉沒三個相鄰的點(diǎn)a, b, c求叉積Pab×Pac。每一組Pab×Pac 都同號則說明多多邊形是叉積。

2、判圓心是否在多邊形每部。枚舉相鄰的兩個點(diǎn)a,b,設(shè)圓心左邊為c,然后同1,求叉積,判符號。

3、求圓心到多邊形每條邊的距離,與半徑比較,如果小于半徑則PEG WILL NOT FIT。設(shè)一條邊的兩個端點(diǎn)為a, b,圓心為c。這里可以用叉積求三角形Sabc的面積和ab的長度L。c到ab的距離就是Sabc/L。

ps:第一次提交的時候條件1判錯了,wa了一次。T_T

?

?

View Code #include <iostream> #include <cstring> #include <cstdio> #include <cmath>using namespace std;const int N = 1100; const double eps = 1e-8;struct point {double x;double y; }p[N], cir;double rad; int n;int dbcmp(double x) {if(x > eps) return 1;else if(x < -eps) return -1;return 0; }double det(double x1, double y1, double x2, double y2) {return x1*y2 - x2*y1; }double cross(point a, point b, point c) { //叉積return det(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y); }double dis(point a, point b, point c) { //求點(diǎn)到邊的距離double s, l;s = fabs(cross(c, a, b)); //Sabc * 2l = sqrt((b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)); //Lreturn s/l; }void solve() {double flag, t, d;int i;flag = cross(p[0], p[1], p[2]);for(i = 1; i < n-1; ++i) { //判是否為凸包t = cross(p[i], p[i+1], p[i+2]);if(dbcmp(flag*t) < 0) {puts("HOLE IS ILL-FORMED"); return ;}}flag = cross(p[0], p[1], cir);d = dis(p[0], p[1], cir);if(dbcmp(rad - d) > 0) {puts("PEG WILL NOT FIT"); return ;}for(i = 1; i < n; ++i) { //判圓是否在多邊形內(nèi)并且圓心到直線的距離 <= radiu d = dis(p[i], p[i+1], cir);t = cross(p[i], p[i+1], cir);if(dbcmp(flag*t) < 0) {puts("PEG WILL NOT FIT");return ;}if(dbcmp(rad - d) > 0) {puts("PEG WILL NOT FIT"); return;}}puts("PEG WILL FIT"); }int main() {//freopen("data.in", "r", stdin);int i;while(~scanf("%d", &n)) {if(n < 3) break;scanf("%lf%lf%lf", &rad, &cir.x, &cir.y);for(i = 0; i < n; ++i) {scanf("%lf%lf", &p[i].x, &p[i].y);}p[n] = p[0];solve();}return 0; }

?

POJ 2187

題意很清楚,求凸包的直徑。表示不會旋轉(zhuǎn)卡殼,只能暴力的來做。黑書上的Graham-Scan算法。O(n)的時間復(fù)雜度求凸包,然后對極點(diǎn)兩兩枚舉,求最大距離。感覺這樣寫bug很明顯,50000的數(shù)據(jù)如果都在凸包上,那。。。必定TLE!-_-! 丫的,第一次寫的時候完了排序了。TLE*2 T_T!

渣代碼:375+ms

?

View Code #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm>using namespace std;const int N = 50007; const double eps = 1e-6; const double inf = ~0u;struct point {double x;double y; } p[N];int st[N], f[N], n, t; bool vis[N];int dbcmp(double x) {if(x > eps) return 1;else if(x < -eps) return -1;return 0; }bool cmp(point a, point b) {if((dbcmp(a.y - b.y) == 0)) return dbcmp(a.x - b.x) < 0;return dbcmp(a.y - b.y) < 0; }double det(double x1, double y1, double x2, double y2) {return x1*y2 - x2*y1; }double cross(point a, point b, point c) {return det(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y); }double dis(point a, point b) {return (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y); }void graph(int dir) { //Graham求凸包int i;t = 0;for(i = 0 ; i < n; ++i) {if(vis[i]) continue;while(t > 1 && cross(p[st[t-1]], p[st[t]], p[i])*dir < 0) --t;st[++t] = i;}for(i = 2; i < t; ++i) vis[st[i]] = true; }int main() {//freopen("data.in", "r", stdin);int i, m, j;double res, tmp;scanf("%d", &n);for(i = 0; i < n; ++i) {scanf("%lf%lf", &p[i].x, &p[i].y);}sort(p, p + n, cmp);memset(vis, false, sizeof(vis));graph(1);for(i = 1; i <= t; ++i) f[i] = st[i]; m = t;graph(-1);for(i = 1; i < t; ++i) f[m+i] = st[t-i]; m += (t - 1);res = -inf;for(i = 1; i < m - 1; ++i) {for(j = i + 1; j < m; ++j) {tmp = dis(p[f[i]], p[f[j]]);if(tmp > res) res = tmp;}}printf("%.0f\n", res);return 0; }

?

?POJ 1113

題意是給一組點(diǎn)的坐標(biāo)表示的多邊形,要從外圍用繩子圍起來,并且繩子到多邊形的最短距離為L。求繩子的最短長度。

很明顯,找出凸包,然后求各相鄰極點(diǎn)間的距離,最后加上半徑為L的圓的周長。

View Code #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm>using namespace std;const int N = 1024; const double eps = 1e-6; const double pi = acos(-1.0);struct point {double x;double y; } p[N];int st[N], t, n; bool vis[N]; int f[N];int dbcmp(double x) {if(x > eps) return 1;else if(x < -eps) return -1;return 0; }bool cmp(point a, point b) {if(dbcmp(a.y - b.y) == 0) return dbcmp(a.x - b.x) < 0;return dbcmp(a.y - b.y) < 0; }double det(double x1, double y1, double x2, double y2) {return x1*y2 - x2*y1; }double cross(point a, point b, point c) {return det(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y); }double dis(point a, point b) {return sqrt((b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)); }void graham(int dir) {int i; t = 0;for(i = 0; i < n; ++i) {if(vis[i]) continue;while(t > 1 && dir*cross(p[st[t-1]], p[st[t]], p[i]) < 0) --t;st[++t] = i;}for(i = 2; i < t; ++i) vis[st[i]] = true; }int main() {//freopen("data.in", "r", stdin);int i, m;double l, res;while(~scanf("%d%lf", &n, &l)) {for(i = 0; i < n; ++i) {scanf("%lf%lf", &p[i].x, &p[i].y);}sort(p, p + n, cmp);memset(vis, 0, sizeof(vis));graham(1);for(i = 1; i <= t; ++i) f[i] = st[i]; m = t;graham(-1);for(i = 1; i < t; ++i) f[m + i] = st[t - i]; m += t-1;res = 0;for(i = 1; i < m; ++i) {res += dis(p[f[i]], p[f[i + 1]]);}res += 2*pi*l;printf("%.0lf\n", res);}return 0; }

?

?

?ps:計(jì)算幾何這幾道水題終于刷完了,有的地方確實(shí)很惡心人。。。比如說POJ 1408,YY題,因?yàn)椴皇?#xff0c;我敲了一個晚自習(xí)。。。發(fā)現(xiàn)計(jì)算幾何的模板好多,記記模板,加油!^_^

?

?

?

?

?

?

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的POJ 计算几何的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。