• 【刷题-考研上机模拟】综合模拟2-2019浙大上机模拟(晴神)


    A - next[i]

    Problem Description

    在字符串匹配的KMP算法中有一个重要的概念是next数组,求解它的过程让不少同学伤透了心。next数组的直接语义其实是:使“长度为L的前缀”与“长度为L的后缀”相同的最大L,且满足条件的前后缀不能是原字符串本身。

    例如对字符串"ababa"来说,长度为1的前缀与后缀都是"a",它们相同;长度为2的前缀与后缀分别是"ab"和"ba",它们不相同;长度为3的前缀与后缀都是"aba",它们相同;长度为4的前缀与后缀分别是"abab"和"baba",它们不相同。因此对字符串"ababa"来说,使“长度为L的前缀”与“长度为L的后缀”相同的最大L是3。

    现在我们把这个最大的L值称为原字符串S的next值。在此概念的基础上,对给定的字符串S,下标为从1到N,那么next[i]就是指子串S[1...i]的next值。

    现在给定一个字符串,下标从1到N,然后给一个下标i,求next[i]。

    Input

    每个输入文件一组数据。

    只有一行,输入一个仅由小写字母组成的长度为N(1<=N<=100)的字符串、与一个下标i(1<=i<=N)。

    Output

    一个整数,即next[i]。

    Sample Input 1

    ababa 5
    

    Sample Output 1

    3
    

    Sample Input 2

    ababab 4
    

    Sample Output 2

    2
    

    Sample Input 3

    ab 2
    

    Sample Output 3

    0
    

    分析:掌握具体算法即可,算法详解见KMP算法

    #include<bits/stdc++.h>
    using namespace std;
    void buildNext(string str, int nt[]){
        int len = str.size();
        nt[0] = -1;
        int t = nt[0], j = 0;
        while(j < len - 1){
            if(t < 0 || str[j] == str[t]){
                nt[++j] = ++t;
            }else{
                t = nt[t];
            }
        }
    }
    int main(){
        int nt[110];
        string str;
        cin>>str;
        buildNext(str, nt);
        int index;
        cin>>index;
        cout<<nt[index - 1] + 1<<endl;
        return 0;
    }
    

    B - 链表重排

    Problem Description

    给定一条单链表,将链表结点进行头尾交错重新排序,即如果一条单链表为 L1 -> L2 -> ... -> L(n-1) -> Ln ,那么重新排序完的结果是 L1 -> Ln -> L2 -> L(n-1) -> L3 -> L(n-2) -> ...

    Input

    每个输入文件中一组数据。

    第一行给出结点的总个数N(0<N<10^5)和单链表的第一个结点的地址。所有结点的地址要么是一个五位正整数,要么是用-1表示的空地址NULL。然后是N行,表示N个结点,每行的格式为

    Address Data Next

    其中Address为结点地址(不足5位的高位用零填充至5位),Data为结点的数据域(绝对值不超过10^5的整数),Next为结点的指针域(即下一个结点的地址)。数据保证Address不等于-1。

    Output

    输出按题目要求重新排序后的单链表。第一行为重新排序后单链表上结点的个数、第一个结点的地址。

    之后每行一个结点,输出格式与输入相同,结点输出顺序为单链表连接顺序。

    Sample Input

    5 11111
    33333 0 44444
    22222 2 33333
    11111 5 22222
    05689 8 -1
    44444 6 05689
    

    Sample Output

    5 11111
    11111 5 05689
    05689 8 22222
    22222 2 44444
    44444 6 33333
    33333 0 -1
    

    分析:

    1. 链表的长度要自己计算,不是所有的节点都会用到

    2. 链表可能是空的

    #include<bits/stdc++.h>
    using namespace std;
    const int nmax = 100010;
    int data[nmax], nt[nmax], lt[nmax];
    int main(){
        int n, head;
        cin>>n>>head;
        for(int i = 0; i < n; i++){
            int addr;
            cin>>addr;
            cin>>data[addr]>>nt[addr];
        }
        int len = 0;
        while(head != -1){
            lt[len++] = head;
            head = nt[head];
        }
        vector<int>ans;
        int i = 0, j = len - 1;
        while(i <= j){
            ans.push_back(lt[i++]);
            if(i < j)ans.push_back(lt[j--]);
        }
        if(ans.size() == 0){
            printf("0 -1");
            return 0;
        }
        printf("%d %05d
    ", ans.size(), ans[0]);
        for(int i = 0; i < ans.size() - 1; ++i){
            printf("%05d %d %05d
    ", ans[i], data[ans[i]], ans[i + 1]);
        }
        printf("%05d %d -1
    ", ans.back(), data[ans.back()]);
        return 0;
    }
    

    C - 极大匹配

    Problem Description

    对给定的无向图G=(V,E),如果边集E'满足:(1)E'是E的子集;(2)E'中的任意两条边都没有公共顶点,那么称边集E'为图G的一个匹配(Matching)。而如果往E'中增加任意一条在E中但不在E'中的边,都会导致E'不再是图G的匹配,那么称E'为图G的一个极大匹配(Maximal Matching)。
    (以上定义引自https://en.wikipedia.org/wiki/Matching_(graph_theory)

    根据上面的定义,请判断一些给定的边集是否是给定的无向图的极大匹配。

    Input

    每个输入文件一组数据。

    第一行两个整数N、M(1<=N<=1000, 0<=M<=N*(N-1)/2),表示顶点数和边数,假设所有顶点的编号为1到N。

    接下来M行,每行两个正整数u、v(1<=u,v<=N, u!=v),表示一条边的两个端点编号。

    然后一个正整数K(K<=10),表示查询个数。

    接下来为K个查询,每个查询第一行为一个正整数L,表示待查询边集的边数,接下来L行每行两个正整数,表示一条边的两个端点编号。数据保证每个查询中相同的边只会出现一次,且所有边都在图中存在。

    Output

    每个查询输出一行,如果给定的边集是极大匹配,那么输出Yes;如果它是匹配但不是极大匹配,那么输出Not Maximal;如果不是匹配,那么输出Not a Matching

    Sample Input

    4 4
    1 2
    1 3
    2 3
    2 4
    4
    1
    2 3
    1
    1 3
    2
    1 2
    2 4
    2
    1 3
    2 4
    

    Sample Output

    Yes
    Not Maximal
    Not a Matching
    Yes
    

    Solution

    #include<bits/stdc++.h>
    using namespace std;
    const int nmax = 1010;
    bool vis[nmax], G[nmax][nmax], tempG[nmax][nmax];
    struct node{
        int u, v;
    };
    int main(){
        int n, m, K, L;
        vector<node>E;
        cin>>n>>m;
        fill(G[0], G[0] + nmax * nmax, false);
        for(int i = 0; i < m; ++i){
            int u, v;
            cin>>u>>v;
            G[u][v] = G[v][u]  =true;
            E.push_back({u, v});
        }
        cin>>K;
        for(int i  =0; i < K; ++i){
            vector<node>tempE;
            fill(vis, vis + nmax, false);
            fill(tempG[0], tempG[0] + nmax * nmax, false);
            cin>>L;
            bool flag = true;
            for(int j = 0; j < L; ++j){
                int u, v;
                cin>>u>>v;
                if(G[u][v] == false)flag = false;
                if(vis[u] == true || vis[v] == true)flag = false;
                tempG[u][v] = tempG[v][u] = true;
                tempE.push_back({u, v});
                vis[u] = vis[v] = true;
            }
            if(flag == false)printf("Not a Matching
    ");
            else{
                for(int j = 0; j < E.size(); ++j){
                    int u = E[j].u, v = E[j].v;
                    if(tempG[u][v] == false){
                        if(vis[u] == false && vis[v] == false){
                            flag = false;
                            break;
                        }
                    }
                }
                if(flag == true)printf("Yes
    ");
                else printf("Not Maximal
    ");
            }
        }
        return 0;
    }
    

    D - 关键路径

    Problem Description

    给定一个有N个顶点、M条边的有向图,顶点下标为从1到N,每条边都有边权。判断这个有向图是否是有向无环图,如果是的话,请处理K个查询,每个查询为图中的一条边,求这条边的最早发生时间和最晚发生时间。最后再输出图中的所有关键路径。

    Input

    每个输入文件中一组数据。

    第一行为两个整数N、M,表示有向无环图的顶点数和边数(1<=N<=1000, 0<=M<=N*(N-1)),顶点编号为从1到N。

    接下来M行,每行为三个正整数u、v、w(1<=u,v<=N,0<w<=20,u!=v),分别表示有向边的起点、终点、边权。数据保证不会有两条起点和终点都相同的边。

    然后是一个正整数K(1<=K<=1000),表示查询个数。

    接着是K行,每行为两个正整数u、v,分别表示查询边的起点和终点。数据保证查询边一定是图上存在的边。

    Output

    如果给出的图不是有向无环图,那么在一行里输出NO,后面的查询结果和关键路径均不需要输出;

    如果给出的图是有向无环图,那么在一行里输出YES,接着输出下面的内容:

    每个查询一行,输出查询边的最早发生时间和最晚发生时间;

    之后一行输出一个整数:关键路径上的边权之和;

    最后若干行输出所有关键路径,每行表示其中一条,格式为用->连接的顶点编号。注意,如果有两条关键路径a[1]->a[2]->...->a[k]->a[k+1]->...与b[1]->b[2]->...->b[k]->[k+1]->...,满足a[1]==b[1]、a[2]==b[2]、...、a[k]==b[k]、a[k+1]<b[k+1],那么把关键路径a优先输出。数据保证关键路径条数不超过10000条。

    Sample Input 1

    4 5
    1 2 3
    1 3 2
    1 4 5
    2 4 1
    3 4 3
    2
    1 3
    2 4
    

    Sample Output 1

    YES
    0 0
    3 4
    5
    1->3->4
    1->4
    

    Sample Input 2

    3 3
    1 2 3
    2 3 1
    3 2 2
    2
    1 2
    2 3
    

    Sample Output 2

    NO
    

    分析:

    1.多个有向图

    2.多起点、多汇点

    3.图中存在孤立点,此时入度也为0

    求关键路径时,将存关键路径上的边而非关键活动,使用邻接表而非邻接矩阵

    #include<bits/stdc++.h>
    using namespace std;
    const int nmax = 1010;
    struct node{
        int v, w;
    };
    vector<node>G[nmax];
    vector<int>activity[nmax];
    int n, m, inDeg[nmax] = {0}, inDegOrigin[nmax] = {0};
    int ve[nmax], vl[nmax];
    int e[nmax][nmax], l[nmax][nmax];
    stack<int>topOrder;
    bool topologicalSort(){
        queue<int>q;
        for(int i = 1; i <= n; ++i){
            if(inDeg[i] == 0)q.push(i);
        }
        while(!q.empty()){
            int u = q.front();
            q.pop();
            topOrder.push(u);
            for(int i = 0; i < G[u].size(); ++i){
                int v = G[u][i].v;
                inDeg[v]--;
                if(inDeg[v] == 0)q.push(v);
                ve[v] = max(ve[v], ve[u] + G[u][i].w);
            }
        }
        if(topOrder.size() == n)return true;
        else return false;
    }
    int criticalPath(){
        fill(ve, ve + nmax, 0);
        if(topologicalSort() == false)return -1;
        int maxLen = -1;
        for(int i = 1; i <= n; ++i){
            if(ve[i] > maxLen)maxLen = ve[i];
        }
        fill(vl, vl + nmax, maxLen);
        while(!topOrder.empty()){
            int u = topOrder.top();
            topOrder.pop();
            for(int i = 0; i < G[u].size(); ++i){
                int v = G[u][i].v;
                vl[u] = min(vl[u], vl[v] - G[u][i].w);
            }
        }
        for(int u = 1; u <= n; ++u){
            for(int i = 0; i < G[u].size(); ++i){
                int v = G[u][i].v, w = G[u][i].w;
                e[u][v] = ve[u];
                l[u][v] = vl[v] - w;
                if(e[u][v] == l[u][v])activity[u].push_back(v);
            }
        }
        return maxLen;
    }
    vector<int>path;
    void dfs(int u){
        if(activity[u].size() == 0){
            path.push_back(u);
            int flag = 0;
            for(int x : path){
                if(flag == 1)printf("->");
                printf("%d", x);
                flag = 1;
            }
            printf("
    ");
            path.pop_back();
            return;
        }
        path.push_back(u);
        sort(activity[u].begin(), activity[u].end());
        for(int x : activity[u]){
            dfs(x);
        }
        path.pop_back();
    }
    int main(){
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; ++i){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            G[u].push_back({v, w});
            inDeg[v]++;
            inDegOrigin[v]++;
        }
        int maxLen = criticalPath();
        if(maxLen == -1)printf("NO
    ");
        else{
            printf("YES
    ");
            int k;
            scanf("%d", &k);
            for(int i = 0; i < k; ++i){
                int u, v;
                scanf("%d%d", &u, &v);
                printf("%d %d
    ", e[u][v], l[u][v]);
            }
            printf("%d
    ", maxLen);
            for(int i =1; i <= n; ++i){
                if(inDegOrigin[i] == 0 && activity[i].size() != 0)dfs(i);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    js拖拽效果 javascript实现将元素拖拽如某容器效果demo
    使用 transform3D 造成网页闪动的底层原因剖析
    设置文字垂直 竖向 显示
    文本光标,高亮选中一些出来
    HTMl5的sessionStorage和localStorage
    event 事件兼容性处理 keycode 大全
    收藏个支持进度条与文件拖拽上传的js File Uploader
    three.js 3D效果
    Winform下的地图开发控件(GMap.NET)使用心得
    ASP.NET Forms验证 实现子域名(SubDomain)共享登陆下的缺陷
  • 原文地址:https://www.cnblogs.com/vinnson/p/10844947.html
Copyright © 2020-2023  润新知