zoj 1158 || poj 1066 Treasure Hunt

211 篇文章 0 订阅
134 篇文章 1 订阅

这个题。。无语啦。

好吧。

第一反应,建图,最短路。想了想,时间可能有点卡。写了好长。N^3的算法。跑了300+ms。。

看人家都是0ms,纠结啊。看了下discuss,见有提到直接判断交点个数!!!囧啊!!!

说的是啊。既然要通过门,那么肯定要通过这个线段的某一点,到达另外一个门。通过几个墙,那么就是经过几扇门到达另外一个点。

这样的话,直接枚举围墙的中点,求最多交点个数即可。

zoj也有这题,PE数次,惭愧。。


我的dijkstra建图。。我好伟大。。

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 40;
const int MAX_N = MAX*MAX;
const double eps = 1e-6;
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == y
struct point{
	double x, y;
	point(){};
	point(double xx, double yy):x(xx), y(yy){}
	bool operator==(const point &a)
	{
		return dd(x, a.x) && dd(y, a.y);
	}
	void get()
	{
		scanf("%lf%lf", &x, &y);
	}
};
struct line{
	point a, b;
};
point l2l_inst_p(line l1,line l2)
{
	point ans = l1.a;
	double t = ((l1.a.x - l2.a.x)*(l2.a.y - l2.b.y) - (l1.a.y - l2.a.y)*(l2.a.x - l2.b.x))/
			   ((l1.a.x - l1.b.x)*(l2.a.y - l2.b.y) - (l1.a.y - l1.b.y)*(l2.a.x - l2.b.x));
	ans.x += (l1.b.x - l1.a.x)*t;
	ans.y += (l1.b.y - l1.a.y)*t;
	return ans;
}
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正 
{
	return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
bool onSegment(point a, point b, point c)
{
	if( dd(crossProduct(a,b,c),0.0) && dyd(c.x,min(a.x,b.x)) && 
		xyd(c.x,max(a.x,b.x)) && dyd(c.y,min(a.y,b.y)) && xyd(c.y,max(a.y,b.y)) )
		return true;
	return false;
}
bool s2s_inst(point p1,point p2, point p3, point p4) 
{
	double d1 = crossProduct(p3,p4,p1);
	double d2 = crossProduct(p3,p4,p2);
	double d3 = crossProduct(p1,p2,p3);
	double d4 = crossProduct(p1,p2,p4);
	if( xy(d1 * d2,0.0) && xy(d3 * d4,0.0) ) return true;
			//如果不判端点相交,则下面这句话不需要 
	if( dd(d1,0.0) && onSegment(p3,p4,p1) || dd(d2,0.0) && onSegment(p3,p4,p2)
	 || dd(d3,0.0) && onSegment(p1,p2,p3) || dd(d4,0.0) && onSegment(p1,p2,p4) )
	 	return true;		
	return false;
}
point p[MAX], t[MAX*MAX*MAX], s, lp[MAX][MAX*MAX];
line l[MAX];
int len[MAX];
bool a[MAX_N][MAX_N];
bool cmp(point a, point b)
{
	if( dd(a.x, b.x) )
		return xy(a.y, b.y);
	return xy(a.x, b.x);
}

bool check(point a, point b, int n)
{
	FOR(i, 0, n)
	{
		if( onSegment(l[i].a, l[i].b, a) || onSegment(l[i].a, l[i].b, b) )
			continue;
		if( s2s_inst(a, b, l[i].a, l[i].b) )
			return false;
	}
	return true;
}
bool bian[MAX_N];
int Dijkstra(int from, int n)  // DIJ + 邻接矩阵 
{
	int dis[MAX_N];
	bool used[MAX_N];
	memset(used,false,sizeof(used));
	for(int i=0; i<n; i++)
		dis[i] = INT_MAX;
	dis[from] = 0;
	used[from] = true;
	int now = from;
	for(int i=1; i<n; i++)
	{
		for(int k=0; k<n; k++)
			if( a[now][k] && dis[k] > dis[now] + 1 )
				dis[k] = dis[now] + 1;
				
		int min = INT_MAX;
		for(int k=0; k<n; k++)
			if( !used[k] && dis[k] < min )
				min = dis[now = k];
		used[now] = true;
	}
	
	int min = INT_MAX;
	FOR(i, 0, n-1)
		if( bian[i] && dis[i] < min )
			min = dis[i];
		
	return min;
}

int solve( int n )
{
	memset(len, 0, sizeof(len));
	memset(a, 0, sizeof(a));
	memset(bian, 0, sizeof(bian));
	int cnt = 0;
	FOR(i, 0, n)
		FOR(k, i+1, n)
			if( s2s_inst(l[i].a, l[i].b, l[k].a, l[k].b) )
				lp[k][len[k]++] = lp[i][len[i]++] = l2l_inst_p(l[i], l[k]);
	
	FOR(i, 0, n)
	{
		sort(lp[i], lp[i]+len[i], cmp);
		FOR(k, 1, len[i])
		{
			if( lp[k] == lp[k-1] ) continue;
			if( i >= n - 4 )
				bian[cnt] = true;
			t[cnt++] = point((lp[i][k].x + lp[i][k-1].x)/2, (lp[i][k].y + lp[i][k-1].y)/2);
		}
	}
	t[cnt++] = s;
	
	FOR(i, 0, cnt)
		FOR(k, i+1, cnt)
			if( check(t[i], t[k], n) )
				a[i][k] = a[k][i] = true;
	
	return Dijkstra(cnt-1, cnt);
}

int main()
{
	int n;
	
	while( ~scanf("%d", &n) )
	{
		FOR(i, 0, n)
		{
			l[i].a.get();
			l[i].b.get();
		}
		l[n].a = point(0, 0);
		l[n++].b = point(100, 0);
		
		l[n].a = point(100, 0);
		l[n++].b = point(100, 100);
		
		l[n].a = point(100, 100);
		l[n++].b = point(0, 100);
		
		l[n].a = point(0, 100);
		l[n++].b = point(0, 0);
		
		s.get();
		
		int ans = solve(n);
		printf("Number of doors = %d\n", ans);
	}

return 0;
}



求交点个数的算法

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 40;
const int MAX_N = MAX*MAX;
const double eps = 1e-6;
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == y
struct point{
	double x, y;
	point(){};
	point(double xx, double yy):x(xx), y(yy){}
	bool operator==(const point &a)
	{
		return dd(x, a.x) && dd(y, a.y);
	}
	void get()
	{
		scanf("%lf%lf", &x, &y);
	}
};
struct line{
	point a, b;
};
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正 
{
	return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
bool onSegment(point a, point b, point c)
{
	if( dd(crossProduct(a,b,c),0.0) && dyd(c.x,min(a.x,b.x)) && 
		xyd(c.x,max(a.x,b.x)) && dyd(c.y,min(a.y,b.y)) && xyd(c.y,max(a.y,b.y)) )
		return true;
	return false;
}
bool s2s_inst(point p1,point p2, point p3, point p4) 
{
	double d1 = crossProduct(p3,p4,p1);
	double d2 = crossProduct(p3,p4,p2);
	double d3 = crossProduct(p1,p2,p3);
	double d4 = crossProduct(p1,p2,p4);
	if( xy(d1 * d2,0.0) && xy(d3 * d4,0.0) ) return true;
			//如果不判端点相交,则下面这句话不需要 
	if( dd(d1,0.0) && onSegment(p3,p4,p1) || dd(d2,0.0) && onSegment(p3,p4,p2)
	 || dd(d3,0.0) && onSegment(p1,p2,p3) || dd(d4,0.0) && onSegment(p1,p2,p4) )
	 	return true;		
	return false;
}
point p[MAX], t[MAX*2], s;
line l[MAX];
point C;
bool cmp(point a,point b)  
{  
	double t1 = atan2(a.y - C.y, a.x - C.x);
	double t2 = atan2(b.y - C.y, b.x - C.x);
    if( dd(t1, t2) ) return xy(fabs(a.x),fabs(b.x));
    return xy(t1, t2);  
}
bool cmp_equal(point a, point b)
{
	return a == b;
}
int solve( int n )
{
	int cnt = 0;
	C = point(50, 50);
	FOR(i, 0, n)
	{
		t[cnt++] = l[i].a;
		t[cnt++] = l[i].b;
	}
	sort(t, t+cnt, cmp);
	
	cnt = unique(t, t+cnt, cmp_equal) - t;

	int min = INT_MAX;
	FOR(i, 1, cnt)
	{
		int door = 0;
		if( !(dd(t[i].x, t[i-1].x) || dd(t[i].y, t[i-1].y)) )
			continue;
		point e = point((t[i].x + t[i-1].x)/2, (t[i].y + t[i-1].y)/2);
		FOR(k, 0, n)
			if( s2s_inst(s, e, l[k].a, l[k].b) )
				door++;
		if( door == 0 ) BUG;
		if( door < min )
			min = door;
	}
	return min;
}

int main()
{
	int n;
	
	while( ~scanf("%d", &n) )
	{
		FOR(i, 0, n)
		{
			l[i].a.get();
			l[i].b.get();		
		}
		l[n].a = point(0, 0);
		l[n++].b = point(100, 0);
		
		l[n].a = point(100, 0);
		l[n++].b = point(100, 100);
		
		l[n].a = point(100, 100);
		l[n++].b = point(0, 100);
		
		l[n].a = point(0, 100);
		l[n++].b = point(0, 0);
		
		s.get();
		
		int ans = solve(n);
		printf("Number of doors = %d\n", ans);
	}

return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值