历届试题-合根植物

问题描述   w星球的一个种植园,被分成 m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。   这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。
  如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
输入格式
  第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。
  接下来一行,一个整数k,表示下面还有k行数据(0<k<100000)
  接下来k行,第行两个整数a,b,表示编号为a的小格子和编号为b的小格子合根了。
  格子的编号一行一行,从上到下,从左到右编号。
  比如:5 * 4 的小格子,编号:
  1 2 3 4
  5 6 7 8
  9 10 11 12
  13 14 15 16
  17 18 19 20

2018.4.14 更新 使用并查集解决:
#include<stdio.h>
#include<stdlib.h>

#define N 1000000

void Init( int *gz , int n );
void Change( int *gz , int n );
void Union( int *gz , int p , int q );
int  Find( int *gz , int p );
int  GetCount( int *gz , int n );

/*
并查集 
*/
int main(void){
	int m , n , k ;
	scanf("%d%d", &m , &n );
	int *gz = malloc( (m * n + 1) * sizeof(int) );
	
	Init( gz , m * n );
	
	scanf("%d" , &k );
	Change( gz , k );
	
	printf("%d\n" , GetCount( gz , m*n ) );
	return 0;
}

int  GetCount( int *gz , int n ){
	//最后每一个根是自身的 就是一颗树 
	int i , count = 0 ;
	for( i = 1 ; i <= n ; i ++ ){
		if( gz[i] == i ){
			count ++ ;
		}
	}
	return count ;
}

int  Find( int *gz , int p ){
	//找到 p 所在树根 
	while( p != gz[p] ){
		p = gz[p];
	}
	return p;
}

void Union( int *gz , int p , int q ){
	//合并 p q 所在树 
	int i = Find( gz , p );
	int j = Find( gz , q );
	
	if( i == j ){
		return;
	}
	gz[i] = j ;		
}

void Change( int *gz , int n ){
	int p , q ;
	while( n -- ){
		scanf("%d%d", &p , &q );
		Union( gz , p , q );
	}
}

void Init( int *gz , int n ){
	//初始化 
	int i;
	for( i = 1 ; i <= n ; i ++ ){
		gz[i] = i ;
	}
}


这题蛮简单的,只要将合根植物用链表连起来就可以很简单的解决了

#include<stdio.h>

typedef struct node{
    int num;            //当前植物的编号 
    struct node *Up;    //当前植物上面链接的植物 
    struct node *Down;    //当前植物下面链接的植物 
    struct node *Left;    //当前植物左面链接的植物 
    struct node *Right;    //当前植物右面链接的植物 
}Node;

void init( Node *, int );
void input( Node *, int , int );
void insert( Node *, int, int, int );
void search( Node *, int, int *, int );
void change( Node *, int * );

int main(void){
    int m, n, k, point=0;
    scanf("%d%d%d", &m, &n, &k );
    
    Node tree[m*n];                    //创建拥有m*n个合根植物的tree结构体数组 
    init( tree, m*n );                //初始化tree结构体数组 
    input( tree, k , n );            //输入合根植物连根的情况 
    
    search( tree, m*n, &point, 0 );    //开始搜索合根植物数 
    
    printf("%d\n", point );
    return 0;
}

void change( Node *root, int *ch ){
    ch[root->num - 1] = 1;                                    //更新检测数组 
    if( root->Up != NULL && ch[root->Up->num - 1] == 0 ){    //分别向四个方向搜索是否有连根情况 
        change( root->Up, ch );
    }
    if( root->Down != NULL && ch[root->Down->num - 1] == 0 ){
        change( root->Down, ch );
    }
    if( root->Left != NULL && ch[root->Left->num - 1] == 0 ){
        change( root->Left, ch );
    }
    if( root->Right != NULL && ch[root->Right->num - 1] == 0 ){
        change( root->Right, ch );
    }
}

void search( Node *root, int n, int *pp, int k ){
    static int check[1000 * 1000] = {0}; //检测数组 记录已经搜索过的连根 
    if( k == n ){                        //搜索出口 
        return ;
    }
    if( check[k] == 0 ){                
        change( &root[k], check );        //一个新的合根植物入口,搜索到底 
        ++ *pp;                            //合根植物数量更新 
    }
    search( root, n, pp, k+1 );
}

void insert( Node *root, int head, int tail , int n ){
    if( head == tail - 1 ){
        root[head - 1].Right = &root[tail - 1];
        root[tail - 1].Left  = &root[head - 1];        
    }
    if( head == tail + 1 ){
        root[head - 1].Left  = &root[tail - 1];
        root[tail - 1].Right = &root[head - 1];        
    }
    if( head == tail - n ){
        root[head - 1].Down  = &root[tail - 1];
        root[tail - 1].Up    = &root[head - 1];        
    }
    if( head == tail + n ){
        root[head - 1].Up    = &root[tail - 1];
        root[tail - 1].Down  = &root[head - 1];        
    }
}

void input( Node *root, int k, int n ){
    int head, tail, i;
    for( i = 0 ; i < k ; i ++ ){
        scanf("%d%d", &head, &tail );
        insert( root, head, tail, n );        //更新连根情况 
    }
}

void init( Node *root, int n ){
    int i ;
    for( i = 0 ; i < n ; i ++ ){
        root[i].num = i+1;
        root[i].Up  = NULL;
        root[i].Down= NULL;
        root[i].Left= NULL;
        root[i].Right=NULL;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值