• Potato的暑期训练day#2 ——图论之拓扑排序


    Potato的暑期训练day#2 ——图论之拓扑排序

    题目链接:

    A.http://poj.org/problem?id=2585

    B.http://poj.org/problem?id=1270

    C.http://poj.org/problem?id=1094

    D.http://poj.org/problem?id=3687

    A.Window Pains

    题意:已知一个4*4的方格和各方格可能出现的数字,给出一个方格当前的显示,求出达到当前情况所需要的方格覆盖次序。

    思路:先打出各个方格可能出现数字的表,然后根据当前方格的数字来确定该数在哪些数的上面,与之连边建立有向图拓扑排序即可。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N = 4;
    int G[N][N];
    int deg[9],s;
    vector<int> F[N*N];
    int PO[9][9];
    void init() {
        F[0].push_back(1);
        F[1].push_back(1);F[1].push_back(2);
        F[2].push_back(2);F[2].push_back(3);
        F[3].push_back(3);
        F[4].push_back(1);F[4].push_back(4);
        F[5].push_back(1);F[5].push_back(2);F[5].push_back(4);F[5].push_back(5);
        F[6].push_back(2);F[6].push_back(3);F[6].push_back(5);F[6].push_back(6);
        F[7].push_back(3);F[7].push_back(6);
        F[8].push_back(4);F[8].push_back(7);
        F[9].push_back(4);F[9].push_back(5);F[9].push_back(7);F[9].push_back(8);
        F[10].push_back(5);F[10].push_back(6);F[10].push_back(8);F[10].push_back(9);
        F[11].push_back(6);F[11].push_back(9);
        F[12].push_back(7);
        F[13].push_back(7);F[13].push_back(8);
        F[14].push_back(8);F[14].push_back(9);
        F[15].push_back(9);
    } 
    bool top(int s) {
        int flag = 0;
        queue<int> Q;
        while(!Q.empty()) Q.pop();
        for(int i = 0;i < 9;i++) {
            if(deg[i] == 0) Q.push(i);
        }
        while(!Q.empty()) {
            int u = Q.front();Q.pop();
            for(int i = 0;i < 9;i++) {
                if(PO[u][i]) {
                    deg[i]--;
                    s--;
                    if(!deg[i]) {
                        Q.push(i);
                    }
                }
            }
        }
        if(s == 0) return true;
        else return false;
    }
    bool solve() {
        for(int i = 0;i < N;i++) {
            for(int j = 0;j < N;j++) {
                int u = N * i + j,v = G[i][j];
                for(int k = 0;k < F[u].size();k++) {
                    if(F[u][k] != v) {
                        if(PO[v-1][F[u][k]-1] == 0){
                            deg[F[u][k]-1]++;
                            PO[v-1][F[u][k]-1] = 1;
                            s++;
                        }
                    }
                }
            }
        }
        /*for(int i = 0;i < 9;i++) {
            for(int j = 0;j < 9;j++) {
                printf("%d ",PO[i][j]);
            }
            printf("
    ");
        }*/
        //printf("%d
    ",s);
        if(top(s)) return true;
        else return false;
    }
    int main() {
        char str[20];
        init();
        for(;;) {
            scanf("%s",str);
            if(strlen(str) > 3 && str[3] == 'O') break;
            memset(deg,0,sizeof(deg));
            memset(PO,0,sizeof(PO));
            s = 0;
            for(int i = 0;i < N;i++) 
                for(int j = 0;j < N;j++) 
                    scanf("%d",&G[i][j]);
            if(solve()) printf("THESE WINDOWS ARE CLEAN
    ");
            else printf("THESE WINDOWS ARE BROKEN
    ");
            scanf("%s",str);
        }
        return 0;
    }
    

    B.Following Orders

    题意:给定变量之间形如x<y的约束关系列表,要求按字典序输出满足约束关系的所有变量序列

    思路:由于要输出所有满足约束关系的序列,所以使用dfs回溯的方法优先搜索字典序小的

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<ctype.h>
    #include<map>
    using namespace std;
    char s[100];
    char tt[30];
    int G[30][30];
    int deg[30];
    int cnt,cur;
    char ans[30];
    map<char,int> mp;
    void topsort(int depth) {
        if(depth == cnt) {printf("%s
    ",ans);return ;}
        for(int i = 0;i < cnt;i++) {
            if(deg[i] == 0) {ans[depth] = tt[i];
            --deg[i];
            for(int j = 0;j < cnt;j++) {
                if(G[i][j]) deg[j]--;
            }
            topsort(depth+1);
            ++deg[i];
            for(int j = 0;j < cnt;j++) {
                if(G[i][j]) deg[j]++;
            }
        }}
    }
    int main() {
        for(;;) {
            gets(s);
            int len = strlen(s);
            if(len == 0) break;
            cnt = 0;
            memset(tt,0,sizeof(tt));
            memset(G,0,sizeof(G));
            memset(deg,0,sizeof(deg));
            memset(ans,0,sizeof(ans));
            for(int i = 0;i < len;i++) {
                if(isalpha(s[i])) {
                    tt[cnt++] = s[i];
                } 
            }
            sort(tt,tt+cnt);
            for(int i = 0;i < cnt;i++) {
                mp[tt[i]] = i;
            }
            memset(s,0,sizeof(s));
            gets(s);
            len = strlen(s);
            if(len == 0) break;
            int flag = 0;
            int u,v;
            for(int i = 0;i < len;i++) {
                if(isalpha(s[i]) && !flag) {
                    u = mp[s[i]];
                    flag = 1;
                }
                else if(isalpha(s[i]) && flag) {
                    v = mp[s[i]];
                    flag = 0;
                    G[u][v] = 1;
                    deg[v]++;
                }
            }
           topsort(0);
           printf("
    ");
        }
        return 0;
    }
    

    C.Sorting It All Out

    题意:将需要拓扑排序的边一条一条的给你,让你判断是否可以确定这个序列只有一种情况,还是有多种情况,还是有环。

    思路:bfs判断是否有环,维护入度为0的点的时候,观察是否存在超过1的情况。

    代码:

    #include<vector>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 27;
    int n,m;
    vector<int> G[maxn];
    int in[maxn],deg[maxn];
    char ans[maxn];
    int cnt;
    void init() {
        for(int i = 0;i < n;i++) G[i].clear();
        memset(in,0,sizeof(in));
    }
    bool check(int u,int v) {
        for(int i = 0;i < G[u].size();i++) if(G[u][i] == v) return true;
        return false;
    }
    //传入当前边数
    int topsort() {
        for(int i = 0;i < n;i++) deg[i] = in[i];
        cnt = 0;
        int flag = 1;
        memset(ans,0,sizeof(ans));
        queue<int> Q;
        while(!Q.empty()) Q.pop();
        for(int i = 0;i < n;i++) {
            if(deg[i] == 0) Q.push(i);
        }
        //if(Q.size() > 1) flag = 0; !!!判断是否有多种情况
        while(!Q.empty()) {
            if(Q.size() > 1) flag = 0; 
            int u = Q.front();Q.pop();
            ans[cnt++] = u + 'A';
            int len = G[u].size();
            for(int i = 0;i < len;i++) {
                int v = G[u][i];
                deg[v]--;
                if(deg[v] == 0) {
                    Q.push(v);
                }
            }
        }
        if(cnt < n) return 2;
        else if(cnt == n && flag) return 3;
        else return 1; 
    }
    int main() {
        while(scanf("%d%d",&n,&m) == 2) {
            if(n == 0 && m == 0) break;
            init();
            char s[5];
            int flag,ok = 0,k;  
            for(int i = 0;i < m;i++) {
                scanf("%s",s);
                if(ok) continue;
                int u = s[0] - 'A',v = s[2] - 'A';
                if(check(u,v)) continue;
                in[v]++;
                G[u].push_back(v);
                flag = topsort();
                if(flag == 3) {
                    ok = 1;
                    printf("Sorted sequence determined after %d relations: %s.
    ",i+1,ans);
                }
                else if(flag == 2) {
                    ok = 1;
                    printf("Inconsistency found after %d relations.
    ",i+1);
                }
            }
            if(flag == 1) printf("Sorted sequence cannot be determined.
    ");
        }
        return 0;
    }
    

    D.Labeling Balls

    题意:有N个不同质量的球,重量为1~N,现在满足一些约束(类似于编号a的球比b的轻) 来给这些球贴1-N的标签,如果有多种情况要保证序号小的球质量轻。

    思路:我们先考虑对位置的排序,我们按照1,2,3...N的质量来放球,我们要调整位置的排序使之满足,比如说我们有a<b,从c<d那么我们要保证a的位置在b前面(c,d同理),其次我们要满足序号小的尽量要小,我们放置a和c的时候可能会将a,c较小的贪心放前面,但是我们并不知道b,d是否更小来使得情况更优,所以我们考虑逆向的拓扑排序,我们先来放b,d这样就不会构成矛盾了

    代码:

    #include<cstdio>
    #include<queue>
    #include<vector>
    #include<cstring>
    using namespace std;
    const int maxn = 205;
    int n,m,cnt;
    int deg[maxn];
    int ans[maxn];
    vector<int> G[maxn];
    void topsort() {
        int t = n;
        priority_queue<int> Q;
        while(!Q.empty()) Q.pop();
        for(int i = 1;i <= n;i++) if(!deg[i]) Q.push(i);
        while(!Q.empty()) {
            int u = Q.top();Q.pop();
            ans[u] = t--;
            for(int i = 0;i < G[u].size();i++) {
                int v = G[u][i];
                deg[v]--;
                if(!deg[v]) Q.push(v);
            }
        }
        if(!t) {
            for(int i = 1;i <= n;i++) printf("%d ",ans[i]);
            printf("
    "); 
        }
        else printf("-1
    ");
    }
    bool check(int u,int v) {
        for(int i = 0;i < G[u].size();i++) {
            int t = G[u][i];
            if(t == v) return false;
        }
        return true;
    }
    void init() {
        memset(ans,0,sizeof(ans));
        memset(deg,0,sizeof(deg));
        for(int i = 1;i<=n;i++) G[i].clear();
    }
    int main() {
        int T;
        scanf("%d",&T);
        while(T--) {
            scanf("%d%d",&n,&m);
            init();
            int u,v;
            for(int i = 0;i < m;i++) {
                scanf("%d%d",&u,&v);
                if(check(v,u)) {
                    G[v].push_back(u);
                    deg[u]++;
                }
            }
            topsort();
        }
        return 0;
    }
    
    我现在最大的问题就是人蠢而且还懒的一批。
  • 相关阅读:
    SQLiteStudio免费的mac下的sqlite 客户端工具
    pip python mysqlclient 报各种错
    python Flask安装
    配置本地资源映射路径 addResourceHandlers
    微信支付 统一下单 签名错误
    utf8mb4_bin与utf8_genera_ci
    Java中Synchronized的用法(简单介绍)
    javaScript正则表达式的使用
    中文正则表达式匹配-正则中文匹配
    excel之CMMI-FP功能点估算辅助生成DET、RET、FTR、FP
  • 原文地址:https://www.cnblogs.com/pot-a-to/p/11139337.html
Copyright © 2020-2023  润新知