题目大意:给出一组木棍,若两木棍相交(规范相交,非规范相交部分去除重叠部分)钉一个钉子;
若有木棍和其他所有木棍不相交,钉两个;最后固定所有木棍,所需钉子数;
解题策略:很水的一题,判断线段相交,而且相交情况简单,没什么说的。
之前题意理解复杂,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;
}