【題解】洛谷P3958[NOIP2017]乳酪 並查集/dfs
阿新 • • 發佈:2018-12-14
打了一份並查集一份dfs的程式碼
#include<cstdio> typedef long long ll; const int N=1e3+10; int set[N]; ll n,h,r; struct node{ ll x,y,z; }hole[N];//存點 void init()//初始化代表元全為自己 { for(int i=0;i<=n+1;i++) set[i]=i; } int findset(int x)//查詢代表元 { if(x==set[x]) return x; else return set[x]=findset(set[x]); } void unionset(int x,int y)//並集 { int fx=findset(x); int fy=findset(y); set[fy]=fx; } ll getdis(node a,node b)//返回兩點間的距離的平方 { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z); } int main() { //freopen("in.txt","r",stdin); int t,i,j; scanf("%d",&t); while(t--) { scanf("%lld%lld%lld",&n,&h,&r);//此處沒寫lld扣20 init(); int st=0,ed=n+1;//虛擬的起點終點 for(i=1;i<=n;i++) { scanf("%lld%lld%lld",&hole[i].x,&hole[i].y,&hole[i].z);//此處沒寫lld再扣10 if(hole[i].z<=r)unionset(i,st);//合併起點和i if(hole[i].z>=h-r)unionset(i,ed);//合併終點和i } for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) if(getdis(hole[i],hole[j])<=(4*r*r))unionset(i,j);//將相通的點合併 if(findset(st)==findset(ed))printf("Yes\n");//起點和終點在集合裡說明連通 else printf("No\n"); } return 0; }
//鏈式前向星+dfs #include<cstdio> #include<cstring> #include<queue> #define INF 0x7f7f7f7f; using namespace std; const int N1=2100000;//不開大點會RE const int N2=1100; typedef long long ll; ll n,h,r,tot,flag; //n空洞個數,h高度,r半徑,tot存邊用,flag標記是否有解 int head[N2],vis[N2];//head存邊用,vis標記節點 struct node{ ll x,y,z; }hole[N2];//長寬高 queue<int>q;//存起點 bool e[N2];//標記可行的終點 ll getdis(node a,node b)//返回距離的平方 { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z); } struct Edge{ int to,nextx; ll val; }edge[N1];//鏈式前向星 void addedge(int u,int v) { edge[tot].to=v; edge[tot].nextx=head[u]; head[u]=tot++; }//添邊 void dfs(int u)//搜尋 { if(e[u])//到達終點 { flag=1;//標記為可行 return; } for(int i=head[u];i!=-1;i=edge[i].nextx) { int v=edge[i].to;//下個節點 if(!vis[v])//沒走過 { vis[v]=1;//標記 dfs(v);//遍歷下個節點 if(flag)return;//已經可行不找了 //可以不用回溯了沒啥用 } } } int main() { //freopen("in.txt","r",stdin); int t,i,j; scanf("%d",&t);//測試用例 while(t--) { while(!q.empty())q.pop(); flag=0; tot=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); memset(e,0,sizeof(e));//以上都是初始化 scanf("%lld%lld%lld",&n,&h,&r); for(i=1;i<=n;i++) { scanf("%lld%lld%lld",&hole[i].x,&hole[i].y,&hole[i].z); if(hole[i].z<=r)q.push(i);//可以作為起點 if(hole[i].z>=h-r)e[i]=1;//可以作為終點 } for(i=1;i<=n;i++) for(j=1;j<i;j++) if(getdis(hole[i],hole[j])<=4*r*r)//兩點連通 { addedge(i,j); addedge(j,i); } while(!q.empty()) { int st=q.front(); q.pop(); dfs(st);//從起點開始遍歷 if(flag)break; } if(flag) printf("Yes\n"); else printf("No\n"); } return 0; }
總結
好久以前寫的