NOIP2017奶酪(搜索,并查集)

[今天typora好像和博客园过不去,代码一直无法正常显示,想要更好的观感请移步file:///C:/Users/THTF/Desktop/noip/NOIP2017%E5%A5%B6%E9%85%AA%EF%BC%88%E5%B9%B6%E6%9F%A5%E9%9B%86%EF%BC%8C%E6%90%9C%E7%B4%A2%EF%BC%89.html]

NOIP2017奶酪(并查集,搜索)


题目描述

现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系, 在坐标系中,奶酪的下表面为 z = 0,奶酪的上表面为 z = h。
现在, 奶酪的下表面有一只小老鼠 Jerry, 它知道奶酪中所有空洞的球心所在的坐标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交, Jerry 则可以从奶酪下表面跑进空洞; 如果一个空洞与上表面相切或是相交, Jerry 则可以从空洞跑到奶酪上表面。
位于奶酪下表面的 Jerry 想知道, 在不破坏奶酪的情况下,能否利用已有的空洞跑到奶酪的上表面去?
空间内两点 P1(x1,y1,z1) 、P2(x2,y2,z2) 的距离公式如下: d = $\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2 +(z_1- z_2)^2}$

输入描述:

每个输入文件包含多组数据。
输入文件的第一行,包含一个正整数 T,代表该输入文件中所含的数据组数。
接下来是 T 组数据,每组数据的格式如下:
第一行包含三个正整数 n, h 和 r, 两个数之间以一个空格分开,分别代表奶酪中空洞的数量,奶酪的高度和空洞的半径。
接下来的 n 行,每行包含三个整数 x, y, z, 两个数之间以一个空格分开, 表示空洞球心坐标为 (x,y,z)。

输出描述:

输出文件包含 T 行,分别对应 T 组数据的答案,如果在第 i 组数据中, Jerry 能从下表面跑到上表面,

则输出“Yes”,如果不能,则输出“No”(均不包含引号)。

示例1

输入

复制
3
2 4 1
0 0 1
0 0 3
2 5 1
0 0 1
0 0 4
2 5 2
0 0 2
2 0 4

输出

复制
Yes
No
Yes

备注:

对于 20%的数据, n = 1, 1 ≤ h , r ≤ 10,000,坐标的绝对值不超过 10,000。
对于 40%的数据, 1 ≤ n ≤ 8, 1 ≤ h , r ≤ 10,000,坐标的绝对值不超过 10,000。
对于 80%的数据,1 ≤ n ≤ 1,000, 1 ≤ h , r ≤ 10,000,坐标的绝对值不超过 10,000。
对于 100%的数据, 1 ≤ n ≤ 1,000, 1 ≤ h , r ≤ 1,000,000,000, T ≤ 20,坐标的绝对值不超过 1,000,000,000。

解题报告

首先检讨 考试心态 太不正式 (本来做出题来就不容易竟然还不好好对待 !罪悪は忍び難い!)
对于题目,想到了两种做法(当然都实现挂了只有20分
现在分别记录下来

1.搜索

  • 思路都是差不多的,关键应该是实现洞与洞之间的连接。
  • yxt大佬的提示:可能环状走
  • 不知道离散化+分层效果会怎么样,有时间搞搞

下面上大哥 精炼无比精妙绝伦异彩纷呈 的代码%%%

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1509;
int T,n;
ll h,r;
struct node{
    ll x,y,z;
}a[N];
vector<int> to[N];
bool ok[N],vis[N],ans;

void dfs(int u){
//0肯定不通顶
    if(ok[u]) {
        ans=1;
        return ;
    }
    for(unsigned int i=0;i<to[u].size();i++)
     if(!ans){
        int v=to[u][i];
        if(vis[v]) continue;
        vis[v]=1;
        dfs(v);
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d%lld%lld",&n,&h,&r);
        for(int i = 0; i <= n; i++)  to[i].clear();
        for(int i = 1; i <= n; i++){
            scanf("%lld%lld%lld", &a[i].x, &a[i].y, &a[i].z);
            if(a[i].z - r <= 0) to[0].push_back(i);            //通底
            if(a[i].z + r >= h) ok[i] = 1;        //通顶
            else ok[i] = 0;
        }
        
        ll d=r*r*4;
        for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++)
           if(i!=j){
            ll dis=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)+(a[i].z-a[j].z)*(a[i].z-a[j].z);
            if(dis<=d) to[i].push_back(j);  //看!大哥思维巧妙的地方就在这儿了:人家存的是可以联通的那些鸭qwq
           }
        ans = 0;
        memset(vis,0,sizeof vis);
        dfs(0);
        if(ans) printf("Yes\n");
        else printf("No\n");  
    }
}

下面是蒟蒻错了的20分代码
嗯……题目说从下往上跑,窝没看见,直接从上往下搜了……QAQ不仔细读题gg啊……水样例害人不浅啊……

#include<bits/stdc++.h>
using namespace std; 
#define ll long long 
#define fr(i,n) for(int i = 1; i <= n; i++)
const int N = 1500;
ll t,n,jk[N],bj,len,js;
ll h,a[N],b[N],c[N];
double r;

struct node{
	ll x,y,z;
}yo[N];

int cmp(node a, node b){ 
if(a.z == b.z) return a.x > b.x;
else return a.z > b.z;
}
void dfs(int i){
	 js = 0;
	if(yo[i].z - r <= 0){
		cout << "Yes" << endl;
		js = 1;
		return ;
	}
   for(int z = 1; z <= len; z++)	
	for(int j = len + 1; j <= n; j++){
	 double disf = pow(abs(yo[z].x - yo[j].x),2) + pow(abs(yo[z].y - yo[j].y),2) + pow(abs(yo[z].z - yo[j].z),2);
		if(disf <= 4*r*r) 	dfs(j);	
	}
}

int main(){  
	ios::sync_with_stdio(false);
	cin >> t;
	while(t--){
		bj = 0, len = 0;
		cin >> n >> h >> r;
		 fr(i,n) {
		   cin >> yo[i].x >> yo[i].y >> yo[i].z;
		   if(yo[i].z + r >= h) bj = 1, len++;	
		 }
		 
		if(!bj) {
			cout << "No" << endl;
			continue;
		}
		sort(yo + 1, yo + 1 + n, cmp);
		dfs(1);
		if(!js) cout << "No"<<endl;
	}
	return 0; 
}

并查集

其实和上面那个搜索没多大区别……

//我准备搞个并查集emmmm
//对看了牛客的标签才开始想并查集的( 
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1500;
ll f[N], a[N], b[N], c[N], n, h, r, t;

ll find(ll k){  return f[k] == k?k:f[k] = find(f[k]); }

void add(int x,int y){   f[find(y)] = find(x); }

double dis(ll x,ll y,ll z,ll a,ll b,ll c){  return sqrt((x-a)*(x-a)+(y-b)*(y-b)+(z-c)*(z-c)); }  //距离 
int main()
{
    ios::sync_with_stdio(false);
    cin >> t;
    while(t--){
        cin >> n >> h >> r;
        for(int i = 0; i <= n + 1; i++)  f[i] = i;
        for(int i = 1; i <= n; i++){
            cin >> a[i] >> b[i] >> c[i];
            if(c[i] + r >= h)  add(i,n+1);
            if(c[i] - r <= 0)  add(i,0);
        }
        for(int i = 1; i <= n - 1; i++)
            for(int j = i + 1; j <= n; j++)
                if(dis(a[i], b[i], c[i], a[j], b[j], c[j]) <= 2 * r) add(i,j);  
        
        if(find(0) == find(n+1))  cout << "Yes" << endl;
        else cout << "No" << endl;
    }
    return 0;
}

posted @ 2019-10-31 15:45  QUEKI嶺冬  阅读(466)  评论(0编辑  收藏  举报
/*! Color themes for Google Code Prettify | MIT License | github.com/jmblog/color-themes-for-google-code-prettify */ .pln{color:#4d4d4c}ol.linenums{margin-top:0;margin-bottom:0;color:#8e908c}li.L0,li.L1,li.L2,li.L3,li.L4,li.L5,li.L6,li.L7,li.L8,li.L9{padding-left:1em;background-color:#fff;list-style-type:decimal!important;}@media screen{.str{color:#718c00}.kwd{color:#8959a8}.com{color:#8e908c}.typ{color:#4271ae}.lit{color:#f5871f}.pun{color:#4d4d4c}.opn{color:#4d4d4c}.clo{color:#4d4d4c}.tag{color:#c82829}.atn{color:#f5871f}.atv{color:#3e999f}.dec{color:#f5871f}.var{color:#c82829}.fun{color:#4271ae}} /*下面是我设置背景色,字体大小和字体*/ .cnblogs-markdown code{ background:#fff!important; } .cnblogs_code,.cnblogs_code span,.cnblogs-markdown .hljs{ font-size:16px!important; } .syntaxhighlighter a, .syntaxhighlighter div, .syntaxhighlighter code, .syntaxhighlighter table, .syntaxhighlighter table td, .syntaxhighlighter table tr, .syntaxhighlighter table tbody, .syntaxhighlighter table thead, .syntaxhighlighter table caption, .syntaxhighlighter textarea { font-size: 16px!important; } .cnblogs_code, .cnblogs_code span, .cnblogs-markdown .hljs{ font-family:consolas, "Source Code Pro", monaco, monospace !important; } //以上是代码高亮 /* 文字特效 */