• 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
    ");
            else printf("No
    ");  
        }
    }
    

    下面是蒟蒻错了的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;
    }
    
    
  • 相关阅读:
    jni基础
    Rank Scores
    LeetCode:Longest Substring Without Repeating Characters
    LeetCode: Two Sum
    vim配置
    设计模式眨一眨
    分布式时序数据库InfluxDB
    地图坐标转换
    根据两点间的经纬度计算距离
    解密经纬度数据(火星坐标)
  • 原文地址:https://www.cnblogs.com/phemiku/p/11771617.html
Copyright © 2020-2023  润新知