LeetCode------冗余连接【1】】

题目链接  https://leetcode-cn.com/problems/redundant-connection/

在本问题中, 树指的是一个连通且无环的无向图。

输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。

结果图是一个以组成的二维数组。每一个的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v无向图的边。

返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v

示例 1:

输入: [[1,2], [1,3], [2,3]]
输出: [2,3]
解释: 给定的无向图为:
  1
 / \
2 - 3

示例 2:

输入: [[1,2], [2,3], [3,4], [1,4], [1,5]]
输出: [1,4]
解释: 给定的无向图为:
5 - 1 - 2
    |   |
    4 - 3

注意:

  • 输入的二维数组大小在 3 到 1000。
  • 二维数组中的整数在1到N之间,其中N是输入数组的大小。

思路:逐个去掉某一个边,测试其是否存在环

解法1,使用邻接矩阵,超内存。所以我把链接矩阵改成bool形式,连通使用1表示,否则使用0,(原来链接矩阵使用的是INT_MAX),勉强通过!

class Solution {
public:
    
    bool flag=true;bool INF=0;
    vector findRedundantConnection(vector>& edges) {
        
        const int maxn=1000;
        
        vector temp(maxn,INF);
        vector< vector >  graph(maxn,temp);
        int mn=0;
        int n;
         
        
       for(int i=0;i-1;i--)
       {
       	   
       	   int a=edges[i][0]-1;
       	   int b=edges[i][1]-1;
       	   graph[a][b]=INF;
		   graph[b][a]=INF;
           //print(graph,n);
		   flag=true;
		   dfs(graph);
		   if(!flag) ;//cout<<"have"< >&graph,int n)
 {
       for(int i=0;i >&graph, int node, vector&visit,
               vector&father)
 {
    if(!flag) return;
	int n = graph.size();
    visit[node] = 1;
    //cout<";
                //    tmp = father[tmp];
                //}
                //cout< >&graph)
{
    int n = graph.size();
    vector visit(n, 0); //visit°´ÕÕËã·¨µ¼ÂÛ22.3½Ú·ÖΪÈýÖÖ״̬
    vector father(n, -1);// father[i] ¼Ç¼±éÀú¹ý³ÌÖÐiµÄ¸¸½Úµã
    for(int i = 0; i < n; i++)
        if(visit[i] == 0&&flag)
            dfsVisit(graph, i, visit, father);
}   
    
};

 

解法2:邻接表:

class Solution {
	public:

		bool flag=true;
		int INF=-1;//INT_MAX;
		vector findRedundantConnection(vector>& edges) {
			int mn=0;
			int n;

			for(int i=0; i > G(n); //临界表

			for(int i=0; i-1; i--) {

				int a=edges[i][0]-1;
				int b=edges[i][1]-1;
				int posa,posb;
				for(int j=0; j >&graph,int n) {
			for(int i=0; i >&graph, int node, vector&visit,
		              vector&father) {
			if(!flag) return;
			int n = graph.size();
			visit[node] = 1;
			//cout<";
							tmp = father[tmp];
						}
						cout< >&graph) {
			int n = graph.size();
			vector visit(n, 0); //visit°′????·¨μ???22.3?ú·??aèy??×′ì?
			vector father(n, -1);// father[i] ????±éàú1y3ì?Diμ????úμ?
			for(int i = 0; i < n; i++)
				if(visit[i] == 0&&flag)
					dfsVisit(graph, i, visit, father);
		};

};

解法3 通过并查集

class Solution {
    public static int[] fa;
    public int find(int x){
        return fa[x]==x?x:(fa[x]=find(fa[x]));
    }
    public static int[] res;
    public void merge(int a,int b){
        int x=find(a);
        int y=find(b);
        if(x!=y){
            fa[x]=y;
        }else{
            res=new int[]{a,b};
        }
    }
    public int[] findRedundantConnection(int[][] edges) {
        if(edges==null||edges[0].length==0){
            return new int[2];
        }
        res=null;
        int n=edges.length;
        fa=new int[n+1];
        for(int i=1;i<=n;++i){
            fa[i]=i;
        }
        for(int i=0;i

总结:

一、无向图回路的判断

    对于无向图,判断其是否有回路有四种方法,如下所示:

    1、利用深度优先搜索DFS,在搜索过程中判断是否会出现后向边(DFS中,连接顶点u到它的某一祖先顶点v的边),即在DFS对顶点进行着色过程中,若出现所指向的顶点为黑色,则此顶点是一个已经遍历过的顶点(祖先),出现了后向边,若完成DFS后,则图中有回路;

    2、在图的邻接表表示中,首先统计每个顶点的度,然后重复寻找一个度为1的顶点,将度为1和0的顶点从图中删除,并将与该顶点相关联的顶点的度减1,然后继续反复寻找度为1的,在寻找过程中若出现若干顶点的度都为2 sanzhangpai,则这些顶点组成了一个回路;否则,图中不存在回路。

    3、利用BFS,在遍历过程中,为每个节点标记一个深度deep,如果存在某个节点为v,除了其父节点u外,还存在与v相邻的节点w使得deep[v]<=deep[w]的,那么该图一定存在回路;
    4、用BFS或DFS遍历,最后判断对于每一个连通分量当中,如果边数m>=节点个数n,那么改图一定存在回路。因此在DFS或BFS中,我们可以统计每一个连通分量的顶点数目n和边数m,如果m>=n则return false;直到访问完所有的节点,return true。

二、有向图回路的判断

    对于有向图,判断其是否有回路的方法也有两种,如下所示:

    1、与无向图类似,若在DFS中出现后向边,即存在某一顶点被第二次访问到,则有回路出现;

    2、同样,利用拓扑排序的思想,通过这一步骤来执行拓扑排序,即重复寻找一个入度为0的顶点,将该顶点从图中删除,并将该顶点及其所有的出边从图中删除(即与该点相应的顶点的入度减1),最终若途中全为入度为1的点,则这些点至少组成一个回路。

    对于有向图,具体点就可得到如下分析:

    问题分析:如果图中存在回路,则必包含一个子图为回路。即该子图中所有顶点入度不为0且至少有边指向另外的顶点。
    算法:
    步骤1:按邻接表方式存储图。遍历与每个节点关联的边并统计每个节点的入度。需要O(n+m)次的运算。
    步骤2:删除所有入度为零的顶点及其相发出的边。并将被删除边所指向的顶点的入度减1。
    重复步骤2直到:
    (1)所有顶点被删除(则没有回路)或;
    (2)还有顶顶点但没有入度为零的顶点可删除(则存在回路)。
    算法复杂度分析:
    由于步骤二中的删除边的操作运算复杂度为O(m),删除节点的操作为O(n) 判断节点入度是否为0需要O(n+m)次运算。其中O(n)次为初始入度为零的节点,O(m)次为删除边后导致的入度为零的节点。于是整个算法复杂度为O(m+n)。


 

你可能感兴趣的:(程序片段)