【题解】洛谷P3958[NOIP2017]奶酪 并查集/dfs

匿名 (未验证) 提交于 2019-12-02 22:56:40






打了一份并查集一份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; } 

总结

好久以前写的

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!