算法竞赛入门经典 第六章



  • Home键按下,光标移到该行开头;End键按下,光标移到该行结尾。

    设输入字符串为s[1~i],则用Next[i]表示当前显示屏中s[i]右边的字符在s中的下标

    例如,设Next[1]=2,Next[2]=4,则在实际显示中顺序如下:s[1]s[2]s[4]

    本题用数组模拟链表,就可以灵活地储存各字符之间的相对位置。假设字符串s的最前面存在一个虚拟的s[0],则Next[0]表示显示屏中最左边的字符。再用cur储存光标位置,当前光标位于s[cur]的右边。当cur=0时,光标在显示屏的最左边。再用变量last表示显示屏最后一个字符s[last]。

    $\color{green}{UVa11988-代码}$

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<map>
    #include<stack>
    #include<queue>
    using namespace std;
    const int maxn = 100000 + 5;
    int last, cur, Next[maxn];
    char s[maxn];
    
    int main()
    {
        while (cin >> s + 1) {//把s[0]空出来
            int n = strlen(s + 1);
            last = cur = 0;
            Next[0] = 0;
    
            for (int i = 1;i <= n;i++) {
                char ch = s[i];
                if (ch == '[') cur = 0;//光标跳到最左边
                else if (ch == ']') cur = last;//光标跳到最右边
                else {
                    Next[i] = Next[cur];//s[i]的右边字符的下标是光标所指右边字符的下标
                    Next[cur] = i;//光标所指右边字符下标应该是[右边字符的下标
                    if (cur == last) last = i;//更新最后一个字符的下标
                    cur = i;//移动光标
                }
            }
            //for(int i=0;i<=last;i++)
            //cout << "Next[" << i << "]=" << Next[i] << endl;
            for (int i = Next[0];i != 0;i = Next[i]) {
                cout << s[i];
            }
            cout << endl;
        }
        return 0;
    }
    

  • 模拟双向链表,用一个Link函数实现两结点间的连接

    void Link(int L,int R){
    	right[L]=R;left[R]=L;
    	//左边的结点伸出一条链连向右边
    	//右边的结点伸出一条链连向左边
    }
    

    注意Link操作的先后顺序:Link(X,Y)不会影响Right[Y]

    $\color{green}{UVa12657-代码} $
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<map>
    #include<stack>
    #include<queue>
    #include<cstdio>
    using namespace std;
    
    int Right[1000000 + 10];
    int Left[1000000 + 10];
    int n, m;
    void Link(int L, int R) {
        Right[L] = R;
        Left[R] = L;
    }
    
    
    int main()
    {
        //FILE* stream1;
        //freopen_s(&stream1, "input.txt", "r", stdin);
        //freopen_s(&stream1, "output.txt", "w", stdout);
        int kase = 0;
        while (cin >> n >> m) {
            for (int i = 1;i <= n;i++) {
                Left[i] = i - 1;
                Right[i] = (i + 1) % (n + 1);
                //Right[n]=0;
            }
            Right[0] = 1;
            Left[0] = n;
            int op, X, Y, inv = 0;
    
            while (m--) {
                cin >> op;
                if (op == 4) inv = !inv;
                else {
                    cin >> X >> Y;
                    if (op == 3 && Right[Y] == X) swap(X, Y);
                    if (inv && op != 3) op = 3 - op;//1变2,2变1
                    if (op == 1 && X == Left[Y]) continue;
                    if (op == 2 && X == Right[Y]) continue;
    
                    int LX = Left[X], RX = Right[X], LY = Left[Y], RY = Right[Y];
                    //一定要先储存再重新链接,否则会在链接过程中相互影响
                    if (op == 1) {
                        Link(LX, RX);
                        Link(LY, X);
                        Link(X, Y);
                    }
                    else if (op == 2) {
                        Link(LX, RX);
                        Link(Y, X);
                        Link(X, RY);
                    }
                    else if (op == 3) {
                        if (Right[X] == Y) {
                            Link(LX, Y);
                            Link(Y, X);
                            Link(X, RY);
                        }
                        else {
                            Link(LX, Y);
                            Link(Y, RX);
                            Link(LY, X);
                            Link(X, RY);
                        }
                    }
                }
            }
    
            int b = 0;
            long long ans = 0;
            for (int i = 1;i <= n;i++) {
                b = Right[b];
                if (i % 2 == 1) ans += b;
            }
            //如果是奇数个盒子,最后的翻转不影响结果
            //但偶数个盒子就会影响
            if (inv && n % 2 == 0) ans = (long long)n * (n + 1) / 2 - ans;
            printf("Case %d: %lld\n", ++kase, ans);
        }
        return 0;
    }
    










  • 拓扑排序,注意在DFS过程中判断给定图是否为DAG

    $\color{green}{UVa10305-代码}$
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<map>
    #include<stack>
    #include<queue>
    #include<cstdio>
    using namespace std;
    
    int E[1000 + 10][1000 + 10];
    int vis[100 + 10];
    int topo[100 + 10];
    int n, m, pos;
    bool dfs(int V) {
        vis[V] = -1;
        for (int u = 1;u <= n;u++) {
            if (E[V][u]) {
                if (vis[u] < 0) return false;//存在有向环
                else if (!vis[u] && !dfs(u)) return false;
                //没访问过的新结点进行访问,但过程中出现有向环
            }
        }
        vis[V] = 1;
        topo[pos] = V;
        pos--;
        return true;
    }
    
    bool toposort() {
        for (int u = 1;u <= n;u++) {
            if (!vis[u] && !dfs(u))return false;
        }
        return true;
    }
    
    int main()
    {
        while (cin >> n >> m) {
            if (!n && !m) break;
            memset(E, 0, sizeof(E));
            memset(topo, 0, sizeof(topo));
            memset(vis, 0, sizeof(vis));
            pos = n;
            for (int i = 1;i <= m;i++) {
                int a, b;
                cin >> a >> b;
                E[a][b] = 1;
            }
            if (toposort()) {
                cout << topo[1];
                for (int i = 2;i <= n;i++) cout << " " << topo[i];
                cout << endl;
            }
        }
        return 0;
    }
    

  • 判断有向图是否存在欧拉路径,只要判断以下两点即可:

    1. 最多存在2个结点的出度不等于入度,且其中一个点出度-入度=1,作为起点,另一个点出度-入度=-1,作为终点。
    2. 图是连通图(只要DFS一次就能访问所有的结点)。
    $\color{green}{UVa10129-代码}$
    #include<iostream>
    #include<map>
    #include<cstring>
    using namespace std;
    
    string words[100000 + 10];
    int E[2000][2000],n,cnt,pass;
    
    struct Node {
        int in = 0, out = 0;
        bool vis = false;
    }node[30];
    
    void dfs(int u) {
        node[u].vis = true;
        pass++;
        for (int i = 1;i <= cnt;i++) if (!node[i].vis && E[u][i]) dfs(i);
    }
    
    int main() {
       //FILE* stream1;
       //freopen_s(&stream1, "input.txt", "r", stdin);
       //freopen_s(&stream1, "output.txt", "w", stdout);
        int t;cin >> t;
        while (t--) {
            memset(E, 0, sizeof(E));
            memset(node, 0, sizeof(node));
            map<char, int> m;
            cnt = 0;
            cin >> n;
            for (int i = 1;i <= n;i++) {
                cin >> words[i];
                char begin = words[i][0], end = words[i][words[i].length() - 1];
                if (!m.count(begin)) m[begin] = ++cnt;
                if (!m.count(end)) m[end] = ++cnt;
                E[m[begin]][m[end]] = 1;
                node[m[begin]].out++;
                node[m[end]].in++;
            }
            int start = 0, end = 0, ok = 1, si;
            for (int i = 1;i <= cnt;i++) {
                int k = node[i].in - node[i].out;
                if (k == 0) continue;
                else if (k == 1) end++;
                else if (k == -1) {start++;si = i;}
                else { ok = 0;break; }
            }
            if (ok && start == end && start <= 1) ok = 1;
            else ok = 0;
            pass = 0;
            if (ok && start == 0) dfs(1);
            else if (ok && start == 1) dfs(si);
            if (pass < cnt) ok = 0;
            if (!ok) cout << "The door cannot be opened." << endl;
            else cout << "Ordering is possible." << endl;
        }
        return 0;
    }
    






posted @ 2020-04-07 22:29  StreamAzure  阅读(187)  评论(0编辑  收藏  举报