• ACdream 1236 Burning Bridges 割边 + 去重边


    题目就是求一副图的割边,然后对于那些有重复的边的,不能算做割边。

    思路就是每次加入一条边的时候,判断这条边是否存在过,存在过的话,就把那条边设为inf,表示不能作为割边。于是有了这样的代码

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    
    const int maxn=100000+20;
    struct data {
        int u,v,id;
        int next;
    } e[maxn*2];
    int first[10000+20];
    int num;//??????
    bool isok (int u,int v) {
        //???u????????????
        for (int i=first[u]; i; i=e[i].next) {
            if (e[i].v==v) {
                e[i].id=inf;
                return false;
            }
        }
        return true;
    }
    void add (int u,int v,int id) {
        if (!isok(u,v)) return ;//???????????????
        ++num;
        e[num].u=u;
        e[num].v=v;
        e[num].id=id;
        e[num].next=first[u];
        first[u]=num;
        return ;
    }
    int DFN[10000+20];//???????
    int low[10000+20];//????????
    int when;//?????????
    int root;
    set<int>pr;
    void dfs (int cur,int father) {
        ++when;
        DFN[cur]=when;
        low[cur]=when;
        for (int i=first[cur]; i; i=e[i].next) {
            int v=e[i].v;//cur????v???
            if (!DFN[v]) { //??????
                dfs(v,cur);
                low[cur]=min(low[cur],low[v]);
                if (low[v]>DFN[cur]&&e[i].id!=inf) {
                    pr.insert(e[i].id);
                }
            } else if(v!=father) {
                low[cur]=min(low[cur],DFN[v]);
            }
        }
        return ;
    }
    void init () {
        pr.clear();
        memset(DFN,0,sizeof(DFN));
        memset(low,0,sizeof(low));
        memset (first,0,sizeof first);
        when=0;
        num=0;
        return ;
    }
    int n,m;
    void work () {
        init ();
        for (int i=1; i<=m; i++) {
            int u,v;
            scanf ("%d%d",&u,&v);
            add(u,v,i);
            add(v,u,i);
        }
        root=1;//????
        dfs(1,root);
        printf ("%d
    ",pr.size());
        for (set<int>::iterator it= pr.begin(); it!=pr.end(); ++it) {
            printf ("%d ",*it);
        }
        printf ("
    ");
        return ;
    }
    int main () {
        while (scanf ("%d%d",&n,&m)!=EOF) work ();
        return 0;
    }
    View Code

    240ms过的。但是应该会有些坑爹的图,卡到它TLE的。

    所以这个方法不行

    考虑去重,做到O(m)

    用used[v] = u表示u--v这样有一条边了。

    建立完整张图后,遍历一次,如果重复的话,就去掉就行了。used数组不用清空,因为值u肯定是不同的。

    坑就是出现了两次,才能判断第二条边重复了。那么第一条边怎么设置为inf呢?

    方法就是用一个数组togo[v] = j表示,当前顶点v的上一条边是j。去重即可。

    压缩时间为44ms

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    
    const int maxn=100000+20;
    struct data {
        int u,v,id;
        int next;
    } e[maxn*2];
    int first[10000+20];
    int num;//用到第几条边
    bool isok (int u,int v) {
        //问一下u顶点所有边能不能去这个点
        for (int i=first[u]; i; i=e[i].next) {
            if (e[i].v==v) {
                e[i].id=inf;
                return false;
            }
        }
        return true;
    }
    void add (int u,int v,int id) {
    //    if (!isok(u,v)) return ;//判断是否有重复的边,绝对不是桥
        ++num;
        e[num].u=u;
        e[num].v=v;
        e[num].id=id;
        e[num].next=first[u];
        first[u]=num;
        return ;
    }
    int DFN[10000+20];//第几个被访问到
    int low[10000+20];//最厉害能访问到谁
    int used[10000 + 20];
    int togo[10000 + 20];
    int when;//什么时候被访问到的
    int root;
    set<int>pr;
    void dfs (int cur,int father) {
        ++when;
        DFN[cur]=when;
        low[cur]=when;
        for (int i=first[cur]; i; i=e[i].next) {
            int v=e[i].v;//cur是爸爸,v是儿子
            if (!DFN[v]) { //没访问过的话
                dfs(v,cur);
                low[cur]=min(low[cur],low[v]);
                if (low[v]>DFN[cur]&&e[i].id!=inf) {
                    pr.insert(e[i].id);
                }
            } else if(v!=father) {
                low[cur]=min(low[cur],DFN[v]);
            }
        }
        return ;
    }
    void init () {
        memset(togo, 0, sizeof togo);
        memset(used, 0, sizeof used);
        pr.clear();
        memset(DFN,0,sizeof(DFN));
        memset(low,0,sizeof(low));
        memset (first,0,sizeof first);
        when=0;
        num=0;
        return ;
    }
    int n,m;
    void work () {
        init ();
        for (int i=1; i<=m; i++) {
            int u,v;
            scanf ("%d%d",&u,&v);
            add(u,v,i);
            add(v,u,i);
        }
        for (int i = 1; i <= n; ++i) {
    //        memset(used, 0, sizeof used);
            for (int j = first[i]; j; j = e[j].next) {
                if (used[e[j].v] == e[j].u) {
                    e[j].id = inf;
                    e[togo[e[j].v]].id = inf;
                }
                used[e[j].v] = e[j].u;
                togo[e[j].v] = j;
            }
        }
        root=1;//从根节点
        dfs(1,root);
        printf ("%d
    ",pr.size());
        for (set<int>::iterator it= pr.begin(); it!=pr.end(); ++it) {
            printf ("%d ",*it);
        }
        printf ("
    ");
        return ;
    }
    int main () {
        #ifdef local
        freopen("data.txt", "r", stdin);
        #endif
        while (scanf ("%d%d",&n,&m)!=EOF) work ();
        return 0;
    }
    View Code
  • 相关阅读:
    Android 基于Message的进程间通信 Messenger完全解析
    Android获取TextView显示的字符串宽度
    关于移动App的五个提问
    Android 结合实例学会AsyncTask的用法
    提高 Android 代码质量的4个工具
    高效开发Android App的10个建议
    移动5年 Android生态系统的演进
    最受欢迎的游戏引擎集结号:跨平台篇
    Java程序员转Android开发必读经验分享
    8 个最优秀的 Android Studio 插件
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5886369.html
Copyright © 2020-2023  润新知