leetcode冗余连接问题

leetcode冗余连接问题

问题描述:在本问题中,有根树指满足以下条件的有向图。该树只有一个根节点,所有其他节点都是该根节点的后继。每一个节点只有一个父节点,除了根节点没有父节点。

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

结果图是一个以边组成的二维数组。 每一个边 的元素是一对 [u, v],用以表示有向图中连接顶点 u 和顶点 v 的边,其中 u 是 v 的一个父节点。

返回一条能删除的边,使得剩下的图是有N个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案

思路:有向图变成有向树即变成只有一个节点入度为0,其他入度为1,且联通的图

源代码如下:

class Solution {
    //有向图变成有向树即变成只有一个节点入度为0,其他入度为1,且联通的图
public:
    vector<bool> visited;
    vector<int>  ind;//记录节点的入度
    vector<vector<int>>  index;//记录以当前节点为开头的边在edges中的下标
    vector<vector<int>> tmp;// 入度为0 1 2的集合
    vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
        vector<int> result;
        int length=edges.size();
        Init(edges);//初始化
        if(tmp[0].size()!=0)   //如果有入度为0的,则在入度为2的节点删除一条边,如果没有入度为0的,则删除入度为1的边
            {
                for(int i=length-1;i>=0;i--)   //找最后哪一个
                {
                    if(tmp[2][0]==edges[i][1]-1)   //删除edges[i]并且进行是否联通的判断。
                       {
                           int v=0;
                           Delete(edges[i]);//删除这条边
                           DFS(tmp[0][0],v,edges);
                           if(v==length)  //删除之后连同,得到结果
                             return  edges[i];
                           Recover(edges[i]);  //删除之后不连通,恢复
                       }
                }
            }//只能有一个入度为2的
        else
        {
            for(int i=length-1;i>=0;i--)  //从后向前扫
            {
                for(int j=0;j<tmp[1].size();j++)
                if(edges[i][1]-1==tmp[1][j])   //找到入度为1的下标对应的边
                {
                    int v=0; 
                    Delete(edges[i]);
                    DFS(tmp[1][j],v,edges);
                    if(v==length)
                     return  edges[i];
                    Recover(edges[i]);
                }
            }
        }
        return result;
    }
    void Delete(vector<int> &cur)  //删除指定的边
    {
        ind[cur[1]-1]=ind[cur[1]-1]-1;  //对应节点入度减一
        for(vector<int>::iterator p=index[cur[0]-1].begin();p!=index[cur[0]-1].end();p++)
           if(*p==cur[1]-1)
             {index[cur[0]-1].erase(p);break;
             }
    }
    void Recover(vector<int> &cur)   //恢复删除的边
    {
        for(int i=0;i<visited.size();i++)
            visited[i]=0;
        ind[cur[1]-1]=ind[cur[1]-1]+1;  //对应节点入度加一
        index[cur[0]-1].push_back(cur[1]-1);
    }
    void DFS(int cur,int &v,vector<vector<int>>& edges)//给定图的顶点数目等于边的数目,cur从0开始
    {
        if(visited[cur])  //如果访问过那么结束
            return;
        visited[cur]=1;
        v++;   
        for(int i=0;i<index[cur].size();i++)
        {

            DFS(index[cur][i],v,edges);//访问邻接节点
        }
    }
    void Init(vector<vector<int>>& edges)
    {
        tmp.resize(3);//0 1 2
        int length=edges.size();
        visited.resize(length);   //初始化标志数组为0
        ind.resize(length);       //初始化入度数组
        index.resize(length);     //初始化下标数组
        for(int i=0;i<length;i++)
           {
               ind[edges[i][1]-1]=ind[edges[i][1]-1]+1;//二维数组第二列即为入度
               index[edges[i][0]-1].push_back(edges[i][1]-1);
           }
        for(int i=0;i<length;i++)  //记录下入度为0 1 2的节点下标
        {
            if(ind[i]==0)
              tmp[0].push_back(i);
            else if(ind[i]==1)
              tmp[1].push_back(i);
            else
              tmp[2].push_back(i);
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值