1. 程式人生 > >NOIP2017提高組day2T1題解(乳酪)

NOIP2017提高組day2T1題解(乳酪)

題目連結:乳酪
這道題還是很水的,在下拿了滿分。
並沒有用什麼高階的演算法,我講一下基本思路。
我們把每個洞都視為一個節點。
我們讀入相關資料後,就先進行預處理,通過每個節點的資訊和題目的規定,建立一張無向圖,兩個能相通的洞對應的節點之間有一條無向邊,這樣我們就建立好了一張圖。
在建圖的時候,我們還需要幹一件事,那就是記錄哪些是起點,哪些是終點。
接下來我們就對每一個節點進行bfs就行了,這樣就可以了。
我們再結合程式碼講解一下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector> //保險起見,沒用萬能標頭檔案 using namespace std; //手寫佇列,用於bfs struct gque{ int f,t; int num[1050]; void init(){ f=0;t=0; } void gpush(int n){ num[t++]=n; } int gtop(){ return num[f]; } void gpop(){ f++; } }; gque q; int T; int
n,h,r; //儲存圖 vector<int> mapp[1005]; //儲存起點 vector<int> s; //儲存終點(這樣便於判斷) int tvis[1005]; int indd[1005][3]; int vis[1005]; int sflag,tflag; int flag; //計算兩點距離 long long ggetdist(int xx,int yy,int zz,int xxx,int yyy,int zzz){ long long dist=1LL*(xx-xxx)*(xx-xxx)+1LL*(yy-yyy)*(yy-yyy)+1LL*(zz-zzz)*(zz-zzz); return
dist; } //bfs,為了反作弊,用了自己的名字縮寫 int cgg(int cur){ q.init(); memset(vis,0,sizeof(vis)); q.gpush(cur); vis[cur]=1; while(q.f!=q.t){ int gg=q.gtop(); q.gpop(); for(unsigned int i=0;i<mapp[gg].size();i++){ if(tvis[mapp[gg][i]]){//這樣判斷比較方便 //如果遍歷到了終點,就返回可以 return 1; } if(!vis[mapp[gg][i]]){ q.gpush(mapp[gg][i]); vis[mapp[gg][i]]=1; } } } //沒找到,返回不可以 return 0; } int main(){ freopen("cheese.in","r",stdin); freopen("cheese.out","w",stdout); scanf("%d",&T); while(T--){ scanf("%d%d%d",&n,&h,&r); //讀入點的資料 for(int i=0;i<n;i++){ scanf("%d%d%d",&indd[i][0],&indd[i][1],&indd[i][2]); } //接下來是一堆初始化,由於是多組資料,這非常重要。 memset(tvis,0,sizeof(tvis)); for(int i=0;i<n;i++){ mapp[i].clear(); } s.clear(); sflag=0,tflag=0;//用於記錄是否有終點和起點 for(int i=0;i<n;i++){ flag=0;//用於判斷一個節點是否既是起點又是終點 if(indd[i][2]+r<=0||indd[i][2]-r>=h){ //排除一些無關的節點(即完全在乳酪外面) continue; } if(indd[i][2]<=r&&indd[i][2]>-r){ //存起點 sflag=1; s.push_back(i); flag++; } if(indd[i][2]>=(h-r)&&indd[i][2]<(h+r)){ //存終點 tvis[i]=1; tflag=1; flag++; } if(flag==2){ //如果存在一個節點既是起點又是終點,那麼就直接輸出可以 printf("Yes\n"); break; } for(int j=i+1;j<n;j++){ //遍歷當前節點是否與其他節點聯通(建圖) if(ggetdist(indd[i][0],indd[i][1],indd[i][2],indd[j][0],indd[j][1],indd[j][2])<=1LL*4*r*r){ mapp[i].push_back(j); mapp[j].push_back(i); } } } if(flag==2){ //代表問題已經解決 continue; } if(!tflag||!sflag){ //如果沒有起點或是沒有終點,顯然不行 printf("No\n"); continue; } flag=0;//用於記錄是否有解 //開始bfs for(unsigned int i=0;i<s.size();i++){ //遍歷每一個起點 if(cgg(s[i])){ //如果有解記錄 flag=1; break; } } //輸出結果 if(flag){ printf("Yes\n"); }else{ printf("No\n"); } } return 0; }

總結:真心不難,非常簡單。