UVA 11783 Nail【簡單線段相交判斷 附YY加強版】

題目大意:給出一組木棍,若兩木棍相交(規範相交,非規範相交部分去除重疊部分)釘一個釘子;

                    若有木棍和其他所有木棍不相交,釘兩個;最後固定所有木棍,所需釘子數;

解題策略:很水的一題,判斷線段相交,而且相交情況簡單,沒什麼說的。


之前題意理解複雜,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捷童鞋如是說哭

當前題意下,釘子數ansNail = 1 + 2 = 3。

按照這個題意理解的代碼,怎麼解決,大家思考吧,實際也很簡單,歡迎大家拍磚:

#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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章