zoukankan      html  css  js  c++  java
  • 7.1 NOI模拟赛 凸包套凸包 floyd 计算几何

    avatar
    avatar

    计算几何之所以难学 就是因为太抽象了 不够直观 而且情况很多 很繁琐 甚至有一些东西不清不楚。。

    这道题注意到题目中的描述 一个鸽子在两个点所连直线上也算。

    通过看题解 发现这个地方并非直线而是线段 这不是明摆着坑人..

    先考虑m<=10的做法 可以想到爆搜 然后 就利用直线 点 三角形来判断复杂度(2^mcdot m^3cdot n) 期望得分30.

    其中直线判断的时候 严谨一点是 如果在直线上再判断len的大小 可是当时考试的时候发现题目中的这句话了所以就没管。

    三角形 的话容易转圈叉积来判 三个叉积同方向就说明在三角形中。

    code bf:
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-8
    #define sq sqrt
    #define mod 1000000007
    #define S second
    #define F first
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=300010,maxn=10000010;
    int n,m,cnt,ans=INF;
    int a[MAXN];
    struct wy
    {
    	int x,y;
    	inline bool operator ==(wy a)
    	{
    		return x==a.x&&y==a.y;
    	}
    	inline wy operator -(wy a)
    	{
    		return (wy){x-a.x,y-a.y};
    	}
    }t[MAXN],w[MAXN];
    inline int judge(wy a,wy b)
    {
    	ll ww=(ll)a.x*b.y-(ll)b.x*a.y;
    	if(!ww)return 0;
    	return ww>0?1:-1;
    }
    int b[MAXN];
    inline void dfs(int x,int v)
    {
    	if(v>=ans)return;
    	if(x==m+1)
    	{
    		rep(1,n,w1)
    		{
    			int flag=0;
    			rep(1,v,i)
    			{
    				if(t[w1]==w[b[i]]){flag=1;break;}
    				rep(i+1,v,j)
    				{
    					if(t[w1]==w[b[j]]){flag=1;break;}
    					//判断点是否在一条直线上:
    					if(!judge(w[b[i]]-w[b[j]],t[w1]-w[b[j]])){flag=1;break;}
    					rep(j+1,v,k)
    					{
    						if(t[w1]==w[b[k]]){flag=1;break;}
    						//判断点是否在一个三角形中 要求叉积的值都相等.
    						int c1=judge(w[b[i]]-w[b[j]],t[w1]-w[b[j]]);
    						int c2=judge(w[b[k]]-w[b[i]],t[w1]-w[b[i]]);
    						int c3=judge(w[b[j]]-w[b[k]],t[w1]-w[b[k]]);
    						if(c1==c2&&c2==c3){flag=1;break;}
    					}
    					if(flag)break;
    				}
    				if(flag)break;
    			}
    			if(!flag)return;
    		}
    		ans=v;
    		return;
    	}
    	b[v+1]=x;
    	dfs(x+1,v+1);
    	dfs(x+1,v);
    }
    int main()
    {
    	freopen("lo.in","r",stdin);
    	freopen("lo.out","w",stdout);
    	get(n);get(m);
    	rep(1,n,i)
    	{
    		int get(x),get(y);
    		t[i]=(wy){x,y};
    	}
    	rep(1,m,i)
    	{
    		int get(x),get(y);
    		w[i]=(wy){x,y};
    	}
    	if(m<=10)
    	{
    		dfs(1,0);
    		put(ans==INF?-1:ans);
    		return 0;
    	}
    	put(-1);
    	return 0;
    }
    
    值得注意的是叉积的时候要开longlong. 不然痛失30分。

    进一步考虑 如果是线段而不是直线的话 那么其实由暴力来看就是一些三角形 一些直线 一些点构成了答案。

    这些东西其实只需要把鸽子所围成的凸包上的点都包含其实相当于包含了整体。因为这些点之间连边形成的一定也是一个凸多边形。

    其实就是要求找到一个凸包包含另外一个凸包。

    这个时候 考虑每一个点 然后向原凸包中发出两条切线显然切线一侧的可以是后继 然后连边。

    最后跑floyd即可。最后从i到i的环的最小值就是答案了。

    分析出问题的关键还是从答案的角度考虑:显然答案的点一定不在原凸包内 那只能在凸包外 此时找凸包外一点 然后寻找下一点 其实就是做切线问题了。

    值得一提的是 该特判的特判好 不过没有特判一个点的情况 且是在线段的情况下的。

    code sol:
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 100000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-9
    #define sq sqrt
    #define mod 998244353
    #define S second
    #define F first
    #define pf(x) ((x)*(x))
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=100010,maxn=510;
    int n,m;
    int f[maxn][maxn];
    struct Vec
    {
    	db x,y;
    	bool operator ==(Vec b){return fabs(x-b.x)<=EPS&&fabs(y-b.y)<=EPS;}
    	db operator %(Vec b){return x*b.y-y*b.x;}
    	inline void ni(){x=-x;y=-y;}
    	Vec operator -(Vec b){return (Vec){x-b.x,y-b.y};}
    }a[MAXN],b[maxn];
    typedef Vec P;
    inline int pd(db x,db y){return fabs(x-y)<=EPS?0:x<y?-1:1;}
    int main()
    {
    	freopen("1.in","r",stdin);
    	get(n);get(m);
    	memset(f,0x3f,sizeof(f));
    	rep(1,n,i)get(a[i].x),get(a[i].y);
    	rep(1,m,i)get(b[i].x),get(b[i].y);
    	rep(1,m,i)
    	{
    		int mxid=0,mnid=0,id1=0,id2=0;
    		P mx,mn,tmp;db v1,v2;
    		rep(1,n,j)
    		{
    			if(a[j]==b[i])continue;
    			tmp=a[j]-b[i];
    			db ww=tmp%(a[1]-b[i]);
    			if(mxid==0||pd(tmp%mx,0)<0)mx=tmp,mxid=j;
    			if(mnid==0||pd(tmp%mn,0)>0)mn=tmp,mnid=j;
    			if(id1==0||v1<ww)id1=j,v1=ww;
    			if(id2==0||v2>ww)id2=j,v2=ww;
    		}
    		if(pd((a[id1]-b[i])%(a[id2]-b[i]),0)<0)continue;
    		mx.ni();
    		rep(1,m,j)
    		{
    			if(i==j)continue;
    			tmp=b[j]-b[i];
    			if(pd(mn%tmp,0)<=0&&pd(tmp%mx,0)<=0)f[i][j]=1;
    		}
    	}
    	rep(1,m,k)rep(1,m,i)rep(1,m,j)f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
    	int ans=INF;rep(1,m,i)ans=min(ans,f[i][i]);
    	put(ans==INF?-1:ans);
    	return 0;
    }
    
  • 相关阅读:
    python统计代码总行数(代码行、空行、注释行)
    selenium常用的API(二)浏览器窗口设置
    selenium常用的API(一)截屏
    python中的yield
    python中的lambda、map、reduce、filter
    python中的exec和eval
    MySQL中的information_schema
    单元测试框架Unittest
    MySQL批量修改相同后缀表名
    【python自动化第十一篇】
  • 原文地址:https://www.cnblogs.com/chdy/p/13223606.html
Copyright © 2011-2022 走看看