題目大意:給出一組木棍,若兩木棍相交(規范相交,非規范相交部分去除重疊部分)釘一個釘子;
若有木棍和其他所有木棍不相交,釘兩個;最后固定所有木棍,所需釘子數;
解題策略:很水的一題,判斷線段相交,而且相交情況簡單,沒什么說的。
之前題意理解復雜,YY一下題意,並給出程序,有興趣的看下文:
原版題意代碼:
/* UVA 11783 Nail AC by J_Dark ON 2013/5/4 Time 0.295s */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <vector> #include <algorithm> using namespace std; struct point{ double x, y; point(double p=0, double q=0){ x = p; y = q; } }; struct line{ point a, b; bool use; line(point x, point y){ a = x; b = y; use = false; } }; vector<line> Seg; int segNum; const double eps = 1e-20; ////////////////////////////////// void Input(){ Seg.clear(); double ax, ay, bx, by; for(int i=0; i<segNum; i++){ cin >> ax >> ay >> bx >> by; point start(ax, ay), end(bx, by); Seg.push_back(line(start, end)); } } double Direction(point Pi, point Pj, point Pk){ return (Pj.x-Pi.x)*(Pk.y-Pi.y)-(Pk.x-Pi.x)*(Pj.y-Pi.y); } //判斷pk點是否在線段pi-pj上 bool OnSegment(point Pi, point Pj, point Pk){ if(min(Pi.x, Pj.x) <= Pk.x && max(Pi.x, Pj.x) >= Pk.x && min(Pi.y, Pj.y) <= Pk.y && max(Pi.y, Pj.y) >= Pk.y) return true; return false; } bool isIntersect(line p, line q){ double d1, d2, d3, d4; d1 = Direction(p.a, p.b, q.a); d2 = Direction(p.a, p.b, q.b); d3 = Direction(q.a, q.b, p.a); d4 = Direction(q.a, q.b, p.b); //規范相交 if( d1*d2<0 && d3*d4<0) { return true;} //非規范相交 else if(fabs(d1)<eps && OnSegment(p.a, p.b, q.a)) {return true;} else if(fabs(d2)<eps && OnSegment(p.a, p.b, q.b)) {return true;} else if(fabs(d3)<eps && OnSegment(q.a, q.b, p.a)) {return true;} else if(fabs(d4)<eps && OnSegment(q.a, q.b, p.b)) {return true;} else return false; } void Compute(){ int ansNail = 0; point t; for(int i=0; i<segNum; i++){ for(int k=i+1; k<segNum; k++){ if( isIntersect(Seg[i], Seg[k]) ){ Seg[i].use = Seg[k].use = true; //標記木棍已釘住 ansNail++; } } if(!Seg[i].use) ansNail += 2; //木棍未被釘子釘住 } cout << ansNail << endl; } ////////////////////////////////// int main(){ while(cin >> segNum && segNum) { Input(); Compute(); } return 0; }
YY加強版題意:在原版題目題意基礎上,增加一個條件:
1,若存在多個木棍交與一點,若之前該交點被當前木棍之前的木棍使用過,該交點無效!不能繼續釘釘子!求最后需要釘子數目。
2,原題中不存在上述數據,所以題目瞬間成水題,大家看原題目時看到這張圖片沒:
3,人生就是想太多——周B捷童鞋如是說
按照這個題意理解的代碼,怎么解決,大家思考吧,實際也很簡單,歡迎大家拍磚:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <vector> #include <algorithm> using namespace std; struct point{ double x, y; point(double p=0, double q=0){ x = p; y = q; } }; struct line{ point a, b; bool use; line(point x, point y){ a = x; b = y; use = false; } }; vector<line> Seg; vector<point> Nail; int segNum; const double eps = 1e-20; ////////////////////////////////// void Input(){ Seg.clear(); Nail.clear(); double ax, ay, bx, by; for(int i=0; i<segNum; i++){ cin >> ax >> ay >> bx >> by; point start(ax, ay), end(bx, by); Seg.push_back(line(start, end)); } } //判斷是否為有效Nail bool isCorrectNail(point t){ vector<point>::iterator it; for(it=Nail.begin(); it!=Nail.end(); it++){ //交點之前出現 if(fabs((*it).x - t.x)<eps && fabs((*it).y - t.y)<eps){ return false; } } //交點之前未出現 Nail.push_back(t); return true; } double Direction(point Pi, point Pj, point Pk){ return (Pj.x-Pi.x)*(Pk.y-Pi.y)-(Pk.x-Pi.x)*(Pj.y-Pi.y); } //判斷pk點是否在線段pi-pj上 bool OnSegment(point Pi, point Pj, point Pk){ if(min(Pi.x, Pj.x) <= Pk.x && max(Pi.x, Pj.x) >= Pk.x && min(Pi.y, Pj.y) <= Pk.y && max(Pi.y, Pj.y) >= Pk.y) return true; return false; } bool isIntersect(line p, line q, point &t){ double d1, d2, d3, d4; d1 = Direction(p.a, p.b, q.a); d2 = Direction(p.a, p.b, q.b); d3 = Direction(q.a, q.b, p.a); d4 = Direction(q.a, q.b, p.b); //規范相交 if( d1*d2<0 && d3*d4<0){ t.x = (q.a.x*d2 - q.b.x*d1)/(d2 - d1); t.y = (q.a.y*d2 - q.b.y*d1)/(d2 - d1); return true; } //非規范相交 else if(fabs(d1)<eps && OnSegment(p.a, p.b, q.a)) {t = q.a; return true;} else if(fabs(d2)<eps && OnSegment(p.a, p.b, q.b)) {t = q.b; return true;} else if(fabs(d3)<eps && OnSegment(q.a, q.b, p.a)) {t = p.a; return true;} else if(fabs(d4)<eps && OnSegment(q.a, q.b, p.b)) {t = p.b; return true;} else return false; } void Compute(){ int ansNail = 0; bool ff1, ff2; point t; for(int i=0; i<segNum; i++){ for(int k=i+1; k<segNum; k++){ ff1 = isIntersect(Seg[i], Seg[k], t); if(ff1){ //線段相交 if(isCorrectNail(t)){ //若交點未被線段i之前的釘子使用 Seg[i].use = Seg[k].use = true; //標記線段已釘住 ansNail++; } } } if(!Seg[i].use) ansNail += 2; //未被釘子釘住 } cout << ansNail << endl; } ////////////////////////////////// int main(){ while(cin >> segNum && segNum) { Input(); Compute(); } return 0; }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。