usaco3.4 fence4從一點看多邊形,輸出能看到的邊

來源:互聯網
上載者:User

        題意:從不在多邊形上的一點看多邊形,輸出能看到的邊(看到邊的部分也算,當然只看到一個端點的不算)

        分析:我們可以把那點看作一個光源,然後枚舉從光源發出的光線,直接枚舉每條光線是不可能的。只能枚舉一些特殊的光線,即經過可見端點的光線(枚舉時,看作一個很小的光束)。對於每條這樣的光線,它的光(因為是光束,它的左右也有光)最多可以到達另外一條邊,且這條邊一定是順時針或逆時針尋找到達的第一條邊。那麼這條邊到底可不可以被這束光照到呢?要被照到要滿足的條件:光源到這條邊的過程中,它的光束左右兩邊不能同時被擋住。

        實際操作:我們先把光源能直接看到的端點求出來,那麼邊只能通過下面兩種途徑照到(1)光源能直接看到的端點的附近(座標+0.5)的點也能被看到(2)通過光源與直接看到的端點的光束照到。。。對於第二種情況,注意可能光線還經過別的端點,那時就要看光線的左右是否都被擋住了

/*ID:kgdpgfy1LANG:C++PROG:fence4*/#include<stdio.h>#include<string.h>#include<math.h>#include<iostream>using namespace std;struct point{int x,y;}p[210];int n,x,y,q[210],l,r;bool flag[210],f[210],tag,l1,r1;int Cr(int k,int i,int j)//叉積{if((p[i].x-p[k].x)*(p[j].y-p[k].y)-(p[j].x-p[k].x)*(p[i].y-p[k].y)==0) return 0;else if((p[i].x-p[k].x)*(p[j].y-p[k].y)-(p[j].x-p[k].x)*(p[i].y-p[k].y)<0) return -1;return 1;}bool C(int k,int i,int j)//(n,k)與(i,j)相交?{//p[n].x=x,p[n].y=y;if(Cr(n,k,i)*Cr(n,k,j)>0) return false;if(Cr(i,j,n)*Cr(i,j,k)>0) return false;return true;}bool Cross(int k)//k點是否被看見{int i;for(i=0;i<n;i++)//枚舉每條線段,是不是把k這個點擋住了if(k!=i&&k!=(i+1)%n&&C(k,i,(i+1)%n))return false;return true;}bool O(double xx,double yy,int n,int i,int j)//(xx,yy)點是否被i,j擋住{if(((p[i].x-p[j].x)*(yy-p[j].y)-(xx-p[j].x)*(p[i].y-p[j].y))*((p[i].x-p[j].x)*(p[n].y-p[j].y)-(p[n].x-p[j].x)*(p[i].y-p[j].y))>=0) return false;if(((p[i].x-xx)*(p[n].y-yy)-(p[i].y-yy)*(p[n].x-xx))*((p[j].x-xx)*(p[n].y-yy)-(p[n].x-xx)*(p[j].y-yy))>=0)return false;return true;}bool Line(double xx,double yy,int i,int j)//(xx,yy)是否在i,j的直線上{if(fabs((yy-p[i].y)*(p[j].x-p[i].x)-(p[j].y-p[i].y)*(xx-p[i].x))<0.000000001)return true;return false;}bool OK(double xx,double yy)//(xx,yy)是否可以被看見{int i;for(i=0;i<n;i++){if(O(xx,yy,n,i,(i+1)%n))return false;}return true;}bool Cal(int n,int k,int i,int j)//從點n發出的光經過點k,射到i,j上。i,j是否可被看見{int a1,b1,c1,a2,b2,c2;double x0,y0;a1=p[j].y-p[i].y;b1=p[i].x-p[j].x;c1=p[j].x*p[i].y-p[i].x*p[j].y;a2=p[n].y-p[k].y;b2=p[k].x-p[n].x;c2=p[n].x*p[k].y-p[k].x*p[n].y;x0=(double)(c2*b1-c1*b2)/(a1*b2-a2*b1);//交於(x0,y0)點,往兩邊移一點點,看能不能被看見y0=(double)(a1*c2-a2*c1)/(a2*b1-a1*b2);if(p[k].x!=p[n].x){if(!(l1&&r1))//左右有一端沒被擋住,那麼這條線段就是可被照到的f[i]=true;else if((fabs(p[n].x-l)<fabs(p[n].x-x0))&&(fabs(p[n].x-r)<fabs(p[n].x-x0)))f[i]=false;else f[i]=true;}else{if(!(l1&&r1))f[i]=true;else if((fabs(p[n].y-l)<fabs(p[n].y-y0))&&(fabs(p[n].y-r)<fabs(p[n].y-y0)))f[i]=false;else f[i]=true;}return f[i];}int main(){freopen("fence4.in","r",stdin);freopen("fence4.out","w+",stdout);int i,j,k,head,tail,ii,jj;double xx,yy;while(scanf("%d",&n)!=EOF){scanf("%d%d",&x,&y);p[n].x=x,p[n].y=y;for(i=0;i<n;i++)scanf("%d%d",&p[i].x,&p[i].y);memset(flag,false,sizeof(flag));memset(f,false,sizeof(f));head=tail=0;//掃描可以直接看到的端點for(i=0;i<n;i++){flag[i]=Cross(i);//i點是否可以被看見if(flag[i])q[tail++]=i;}for(i=0;i<n-1;i++)if(flag[i]&&flag[i+1])//兩個端點都可以被看見,那麼這條線段一定能被看見f[i]=true;if(flag[0]&&flag[n-1])f[n-1]=true;while(head!=tail)//光源能直接看到的點的附近的點是否也能被看到{k=q[head++];if(!f[k]){if(p[k].x!=p[(k+1)%n].x){if(p[(k+1)%n].x>p[k].x)xx=p[k].x+0.5;else xx=p[k].x-0.5;yy=((p[(k+1)%n].y-p[k].y)*(xx-p[k].x))/(p[(k+1)%n].x-p[k].x)+p[k].y;}else{xx=p[k].x;if(p[(k+1)%n].y>p[k].y)yy=p[k].y+0.5;else yy=p[k].y-0.5;}if(!Line(xx,yy,k,n)&&OK(xx,yy)) f[k]=true;}if(!f[(k-1+n)%n]){if(p[k].x!=p[(k+n-1)%n].x){if(p[(k-1+n)%n].x>p[k].x)xx=p[k].x+0.5;else xx=p[k].x-0.5;yy=((p[(k-1+n)%n].y-p[k].y)*(xx-p[k].x))/(p[(k-1+n)%n].x-p[k].x)+p[k].y;}else {xx=p[k].x;if(p[(k-1+n)%n].y>p[k].y)yy=p[k].y+0.5;else yy=p[k].y-0.5;}if(!Line(xx,yy,k,n)&&OK(xx,yy)) f[(k-1+n)%n]=true;}}//假設光源與每個能直接看到的端點發出一束光head=0;while(head!=tail){k=q[head++];l1=r1=false;//標記光的兩端是不是有緊挨著的線段if(p[k].x!=p[n].x)//求左右擋著光線的最接近k的點{if(Cr(n,k,(k+1)%n)<0||Cr(n,k,(k-1+n)%n)<0){r1=true;r=p[k].x;}if(Cr(n,k,(k+1)%n)>0||Cr(n,k,(k-1+n)%n)>0) {l1=true;l=p[k].x;}if(l1&&r1) continue;//如果k的兩邊都有線段擋著,顯然光穿不過去for(i=0;i<n;i++){if(i==k) continue;ii=Cr(n,k,i);if(!ii){if((p[n].x-p[k].x)*(p[k].x-p[i].x)>0){if(((Cr(n,i,(i+1)%n)<0||Cr(n,i,(i-1+n)%n)<0))&&(r1==false||fabs(p[k].x-r)>fabs((double)p[k].x-p[i].x))){r1=true;r=p[i].x;}if((Cr(n,i,(i+1)%n)>0||Cr(n,i,(i-1+n)%n)>0)&&(l1==false||fabs(p[k].x-l)>fabs((double)p[k].x-p[i].x))){l1=true;l=p[i].x;}}}}}else{if(Cr(n,k,(k+1)%n)<0||Cr(n,k,(k-1+n)%n)<0){r1=true;r=p[k].y;}if(Cr(n,k,(k+1)%n)>0||Cr(n,k,(k-1+n)%n)>0) {l1=true;l=p[k].y;}if(l1&&r1) continue;for(i=0;i<n;i++){if(i==k) continue;ii=Cr(n,k,i);if(!ii){if((p[n].y-p[k].y)*(p[k].y-p[i].y)>0){if(((Cr(n,i,(i+1)%n)<0||Cr(n,i,(i-1+n)%n)<0))&&(r1==false||fabs(p[k].y-r)>fabs((double)p[k].y-p[i].y))){r1=true;r=p[j].y;}if((Cr(n,i,(i+1)%n)>0||Cr(n,i,(i-1+n)%n)>0)&&(l1==false||fabs(p[k].y-l)>fabs((double)p[k].y-p[i].y))){l1=true;l=p[i].y;}}}}}i=(k+1)%n;while(i!=k)//逆時針找第一個相交的{ii=Cr(n,k,i);jj=Cr(n,k,(i+1)%n);if(ii*jj<0)break;i=(i+1)%n;}if(i!=k&&!f[i]){if(Cal(n,k,i,(i+1)%n)) continue;}j=(k-1+n)%n;while(j!=k)//順時針找第一個相交的{ii=Cr(n,k,j);jj=Cr(n,k,(j-1+n)%n);if(ii*jj<0)break;j=(j-1+n)%n;}if(j!=k&&!f[(j-1+n)%n]){Cal(n,k,(j-1+n)%n,j);}}//輸出for(j=0,i=0;i<n;i++)if(f[i]) j++;if(!j) printf("NOFENCE\n");else{printf("%d\n",j);for(i=0;i<n-2;i++)if(f[i])printf("%d %d %d %d\n",p[i].x,p[i].y,p[i+1].x,p[i+1].y);if(f[n-1])printf("%d %d %d %d\n",p[0].x,p[0].y,p[n-1].x,p[n-1].y);if(f[n-2])printf("%d %d %d %d\n",p[n-2].x,p[n-2].y,p[n-1].x,p[n-1].y);}}return 0;}

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.