P1656 炸铁路

题目:

传送门

 

题解思路:

//大概题解思路:通过枚举的方式,在已知的m条道路中选出一条进行断开,相当于在建立道路联系的时候不将这条道路连上

//然后连接剩余的道路(实质上进行m次这种操作  每次都有一条道路不连接)

//误区:很容易被题目给带偏思路,会考虑先将所有的点通过道路连接,然后再选择炸毁,但不好实现的地方在于炸毁道路两边的点是有同一个祖先

//如何对这些剩余的点重现建立新的祖先,因此我们把这部分归结到修建道路时不建立这条(重复进行m次操作)
 
代码:
#include<iostream>

#include<algorithm>

using namespace std;



const int maxn=150+10;
const int maxx=5000+10;

int n,m;

int a[maxn],b[maxn];

int par[maxn];        //储存祖先结点

int rank1[maxn];       //储存结点所在的高度

// int inde=0;

struct node{

    int a;

    int b;

}temp[maxx];



bool cmp(struct node tt,struct node kk){        //从小到大进行排序

    if(tt.a!=kk.a){         //先比较a 然后比较b

        return tt.a<kk.a;

    }else{

        return tt.b<kk.b;

    }

}



void init(){     //初始化

    for(int i=1;i<=n;i++){      //

        par[i]=i;

        rank1[i]=0;

    }

}



int find(int x){      //查找x祖先

    if(par[x]==x)  return x;        //如果x的祖先就是自己直接返回

    else return par[x]=find(par[x]);    //如果x的祖先不是自己 则需要通过find函数递归找到x的祖先 同时对x的父亲们也一起顺便找共同祖先

}



void unite(int x,int y){

    x=find(x);

    y=find(y);



    if(x==y)    return;



    if(rank1[x]>rank1[y]){

        par[y]=x;

    }else{

        par[x]=y;

        if(rank1[x]==rank1[y]){

            rank1[y]++;

        }

    }

}



bool same(int x,int y){

    if(find(x)==find(y))    return true;

    else return false;

}



int main(){

    cin>>n>>m;

    for(int i=1;i<=m;i++){

        int a,b;

        cin>>a>>b;

        if(a<=b){              //首先这些路的编号进行排序 方便后续直接输出

            temp[i].a=a;

            temp[i].b=b;

        }else{

            temp[i].a=b;

            temp[i].b=a;

        }

    }



    sort(temp+1,temp+m+1,cmp);



    for(int i=1;i<=m;i++){  //枚举m次

        init();

        for(int j=1;j<=m;j++){     //第i条道路不建立

            if(j!=i){

                unite(temp[j].a,temp[j].b);       //道路连接

            }

        }

        //通过判断所有的par是否相同 相同即为有同一个祖先

        

        //或许可以不要下面代码

        int tt=0;

        for(int j=1;j<=n;j++){ //目标不是为了查询祖先  只是为了把所有的祖先进行建立

            tt=find(j);

        }



        int t=par[1];

        int flag=0;

        for(int j=2;j<=n;j++){

            if(t!=par[j]){          //代表有不同的祖先              

                flag=1;

                break;

            }

        }



        if(flag){      

            cout<<temp[i].a<<" "<<temp[i].b<<endl;

        }

    }



    return 0;

}

 

posted @ 2020-10-11 20:25  neverstopcoding  阅读(121)  评论(0编辑  收藏  举报