zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    poj 2312 Battle City
    poj 2002 Squares
    poj 3641 Pseudoprime numbers
    poj 3580 SuperMemo
    poj 3281 Dining
    poj 3259 Wormholes
    poj 3080 Blue Jeans
    poj 3070 Fibonacci
    poj 2887 Big String
    poj 2631 Roads in the North
  • 原文地址:https://www.cnblogs.com/phemiku/p/11771617.html
Copyright © 2011-2022 走看看