题意:给出一个100*100的正方形区域,通过若干连接区域边界的线段将正方形区域分割为多个不规则多边形小区域,然后给出宝藏位置,要求从区域外部开辟到宝藏所在位置的一条路径,使得开辟路径所需要打通的墙壁数最少("打通一堵墙"即在墙壁所在线段中间位置开一空间以连通外界),输出应打通墙壁的个数(包括边界上墙壁)。 思路:枚举每一个入口,在所有的情况中取穿墙数最少的输出即可,枚举每一个入口的时候,并不用枚举每条边的中间点,直接枚举该线段的两个顶点就行(因为要经过一个墙,那么从线段的任意地方进去都行,不必要每次从线段的中点过去),将枚举的顶点与终点(即宝藏所在位置)连成线段,然后就是判断剩下的线段与该线段相交的问题了(注意这里是严格相交),最后得出的数字加1即为结果(因为还有边界墙),还有就是需要特别处理n=0时的情况。
这里说一下我遇到的问题
前期的准备没有什么问题,初始化操作要加上边缘的4个点
#include <iostream> #include <vector> #include <algorithm> #include <string.h> #define eps 1e-10 using namespace std; struct Point { double x,y; Point (double x = 0.0,double y = 0.0):x(x),y(y){} Point operator - (Point p){return Point(x - p.x,y - p.y);} }; vector<Point>ps; struct segment { Point p1,p2; segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){} }; vector<segment> ls; void init() { ps.clear(); ls.clear(); ps.push_back(Point(0.0,0.0)); ps.push_back(Point(100.0,0.0)); ps.push_back(Point(0.0,100.0)); ps.push_back(Point(100.0,100.0)); } double cross(Point p0,Point p1,Point p2) { Point a = p1 - p0; Point b = p2 - p0; return a.x * b.y - a.y * b.x; }
第一个:在判断线段相交的时候是严格相交判断,就是出现两个线段有共同端点的情况(共同端点肯定不是宝藏的点)应该视为一堵墙,就不应视为相交,因为共同端点肯定在最外层,所以一开始我就初始化ans = 1
double ssinset(Point p1,Point p2,Point p3,Point p4) { if(cross(p1,p2,p3) * cross(p1,p2,p4) < -eps && cross(p3,p4,p1) * cross(p3,p4,p2) < -eps)return true; else return false; }
int main() { int n; double x1,y1,x2,y2; while(~scanf("%d",&n)) { init(); for(int i = 0;i < n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); Point a(x1,y1);Point b(x2,y2); ps.push_back(a); ps.push_back(b); ls.push_back(segment(a,b)); } scanf("%lf%lf",&x1,&y1); Point p0(x1,y1); int ret = 0x3f3f3f3f; for(int i = 0;i < ps.size();i++) { int ans = 1; for(int j = 0;j < ls.size();j++) { if(ssinset(ps[i],p0,ls[j].p1,ls[j].p2))ans++; } ret = min(ans,ret); } printf("Number of doors = %d ",ret); } return 0; }
二次AC,我写的时候忘了考虑问题一了(没有进行严格判断,初始化ans = 0)~~