版权声明:仅供研究,转载请注明出处。 https://blog.csdn.net/CSUstudent007/article/details/83447717
首先你要知道如何判断两条线段相交:https://blog.csdn.net/qq826309057/article/details/70942061
思路:
枚举外墙上每道内墙的两个端点和p(宝物)的连线这条线段和内墙的交点的次数最小值即为需要炸墙的最小次数
#include<iostream>
#include<cstdio>
#include<cmath>
#define eps 1e-6
using namespace std;
struct point{
double x,y;
};
struct Line{
struct point a,b;
}lines[35];
bool intersection(const Line &l1,const Line &l2){
//快速排斥
if(max(l2.a.x,l2.b.x)<min(l1.a.x,l1.b.x)||max(l2.a.y,l2.b.y)<min(l1.a.y,l1.b.y)||max(l1.a.x,l1.b.x)<min(l2.a.x,l2.b.x)||max(l1.a.y,l1.b.y)<min(l2.a.y,l2.b.y))
return false;
//跨立实验
double ad_cd=(l1.a.x-l2.b.x)*(l2.a.y-l2.b.y)-(l1.a.y-l2.b.y)*(l2.a.x-l2.b.x);
double bd_cd=(l1.b.x-l2.b.x)*(l2.a.y-l2.b.y)-(l1.b.y-l2.b.y)*(l2.a.x-l2.b.x);
double ac_ab=(l2.a.x-l1.a.x)*(l1.b.y-l1.a.y)-(l2.a.y-l1.a.y)*(l1.b.x-l1.a.x);
double ad_ab=(l2.b.x-l1.a.x)*(l1.b.y-l1.a.y)-(l2.b.y-l1.a.y)*(l1.b.x-l1.a.x);
return ad_cd*bd_cd<=eps&&ac_ab*ad_ab<=eps;
}
int main(){
int n,mmin=100,cnt;
double topx,topy;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lf%lf%lf%lf",&lines[i].a.x,&lines[i].a.y,&lines[i].b.x,&lines[i].b.y);
}
scanf("%lf%lf",&topx,&topy);
if(n==0){
cnt=1;
printf("Number of doors = %d\n",cnt);
return 0;
}
for(int i=0;i<n;i++){
lines[n].a.x=topx;lines[n].a.y=topy;//a端为宝物所在的终点
lines[n].b.x=lines[i].a.x;lines[n].b.y=lines[i].a.y;//b端为外墙上的内墙的端点
cnt=0;
for(int j=0;j<n;j++)
if(intersection(lines[n],lines[j])) cnt++;
mmin=min(mmin,cnt);
lines[n].b.x=lines[i].b.x,lines[n].b.y=lines[i].b.y;
cnt=0;
for(int j=0;j<n;j++)
if(intersection(lines[n],lines[j])) cnt++;
mmin=min(mmin,cnt);
}
printf("Number of doors = %d\n",mmin);
return 0;
}