NOIP2017提高組day2T1題解(乳酪)
阿新 • • 發佈:2019-02-14
題目連結:乳酪
這道題還是很水的,在下拿了滿分。
並沒有用什麼高階的演算法,我講一下基本思路。
我們把每個洞都視為一個節點。
我們讀入相關資料後,就先進行預處理,通過每個節點的資訊和題目的規定,建立一張無向圖,兩個能相通的洞對應的節點之間有一條無向邊,這樣我們就建立好了一張圖。
在建圖的時候,我們還需要幹一件事,那就是記錄哪些是起點,哪些是終點。
接下來我們就對每一個節點進行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;
}
總結:真心不難,非常簡單。