SPOJ-PT07Y Is it a tree DFS/并查集

来源:互联网 发布:用数据包怎么传淘宝 编辑:程序博客网 时间:2024/06/01 08:18

题目描述
You are given an unweighted, undirected graph. Write a program to check if it’s a tree topology.

Input

The first line of the input file contains two integers N and M — number of nodes and number of edges in the graph (0 < N <= 10000, 0 <= M <= 20000). Next M lines contain M edges of that graph — Each line contains a pair (u, v) means there is an edge between node u and node v (1 <= u,v <= N).

Output

Print YES if the given graph is a tree, otherwise print NO.

Example

Input:
3 2
1 2
2 3

Output:
YES
大题意思就是,给你m条边,判断是不是树<->判环。
第一种方法
并查集的思想,对n个点进行初始化,其祖先为其本身,
每次接受一条边的两个点,判断他们的祖先是否相同,如果不同,就将他们连起来,拥有共同祖先,如果相同,则出现了环,
这个很好想,画一个图就清楚了。因为,祖先相同即为-之前这两个点通过某种连接,拥有同一个祖先,这时候,又接受了这一组数据,即这两个点相连,即可推出出现了环->输出NO。
AC代码:

/*2017年7月28日23:14:18SPOJ-PT07YAC思想,找环,找到环就输出NO; 利用并查集的方法 */ #include<stdio.h>const int maxn=1e4+10;int pre[maxn];int find(int x){    int r=x;    while(pre[r]!=r) r=pre[r];    int i=x,j;    while(i!=r){        j=pre[i];        pre[i]=r;        i=j;    }    return r;} void join(int x,int y){    int fx=find(x);    int fy=find(y);    if(fx!=fy){        pre[fx]=fy;    }}int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        pre[i]=i;    }    bool flag=true;    for(int i=1;i<=m;i++){        if(!flag) break;         int a,b;        scanf("%d%d",&a,&b);        int fx=find(a);        int fy=find(b);        if(fx!=fy) pre[fx]=fy;        else{            flag=false;        }    }    if(flag) printf("YES\n");    else printf("NO\n");    return 0;}

第二种方法
代码参考@presenting
暴力DFS,因为数据量也不是很大,利用DFS把扫一遍,对每次扫过的点进行标记,最后再对每个点进行遍历,如果出现了没有访问过的点,则输出NO,因为此时已经不是树了。
AC代码

/*DFS的思想去做2017年7月28日23:18:03SPOJ-PTO7Y     AC*/ #include<stdio.h>#include<string.h>#include<vector>using namespace std;const int maxn=1e4+10;bool vis[maxn];vector<int> e[maxn];void dfs(int i){    if(vis[i]) return;    vis[i]=true;    for(int j=0;j<e[i].size();j++) dfs(e[i][j]);}int main(){    int n,m;    scanf("%d%d",&n,&m);    memset(vis,false,sizeof(vis));    if(m!=n-1||n==1) printf("NO\n");    else{        int s;        for(int i=1;i<=m;i++){            int a,b;            scanf("%d%d",&a,&b);            if(i==1) s=i;             e[a].push_back(b);            e[b].push_back(a);        }        dfs(s);        for(int i=1;i<=n;i++){            if(!vis[i]){                printf("NO\n");                return 0;            }        }        printf("YES\n");    }    return 0;} 

第三种方法
这是一个学弟告诉我的@xzsunbest
首先不能有度为0的点,特殊情况先排除出去
然后每一次操作都把度为1的点去掉,所有跟这个点有边联系的点的度也相应减去1,直到没有度为1的点,这个时候如果还有点剩余,肯定度数都大于等于2,也就是肯定有环存在,不是树。如果全部点都删掉了,就应当是树
代码我没写,我觉得略麻烦,但是这个思路很好

原创粉丝点击