【编程训练-考研上机模拟】综合模拟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\n", ans.size(), ans[0]);
    for(int i = 0; i < ans.size() - 1; ++i){
        printf("%05d %d %05d\n", ans[i], data[ans[i]], ans[i + 1]);
    }
    printf("%05d %d -1\n", 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\n");
        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\n");
            else printf("Not Maximal\n");
        }
    }
    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("\n");
        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\n");
    else{
        printf("YES\n");
        int k;
        scanf("%d", &k);
        for(int i = 0; i < k; ++i){
            int u, v;
            scanf("%d%d", &u, &v);
            printf("%d %d\n", e[u][v], l[u][v]);
        }
        printf("%d\n", maxLen);
        for(int i =1; i <= n; ++i){
            if(inDegOrigin[i] == 0 && activity[i].size() != 0)dfs(i);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/vinnson/p/10844947.html

时间: 2024-10-10 19:03:24

【编程训练-考研上机模拟】综合模拟2-2019浙大上机模拟(晴神)的相关文章

【编程训练-考研上机模拟】综合模拟1-2019浙大上机模拟(晴神)

3月9日综合模拟 A - 古剑奇谭三:封印解除 Problem Description 众所周知,在游戏<古剑奇谭三>中一种被封印的宝箱,而解除封印的过程则是一个小游戏,在这个小游戏中有一个圆盘,如下图所示.为了简单起见,本题只考虑这个小游戏初见时的最简单规则,后续随着游戏主线的推进,这个小游戏会产生好几种变体,转来转去的,会加大本题难度,所以都不考虑了. 可以看到这个圆盘的上下左右各有一块扇状碎片,这四块碎片是可以进出圆盘内外的,而游戏的目标则是让玩家操作上下左右按键,来让这四块扇形最终都处

2019浙大计算机考研机试模拟赛(2)——概念专题

题目链接   引用自晴神OJ A - 边覆盖 B - 极大独立集 C - 稳定婚姻问题 D - 笛卡尔树 没赶得上全程的比赛,就做了两道,后面两道以后有时间再补.两道都是概念题,比较基础~ 以下是题解 A - 边覆盖 Case Time Limit: 200 MS (Others) / 400 MS (Java)       Case Memory Limit: 256 MB (Others) / 512 MB (Java) Accepted: 199      Total Submission

HTTP的请求和相应以及php实现模拟、curl扩展的使用来模拟访问

1.处理不同的图片格式 针对图片处理的公共类兼容多种图片类型的处理. 只要使用不同类型的图片使用不同的imagecreatefrom类型即可实现. [重点!!!] [php实现网络编程] 2.HTTP请求协议[HTTP权威指南已经看了,但是还没有深刻的认识] HTTP用于规范b/s架构中,浏览器和服务器之间信息数据交换的规则.[超文本传输协议对应的(超文本标记语言和数据)] 浏览器和服务器之间建立的TCP连接[连接部分需要注意:三次握手已经不说.持久连接本身占用的资源问题(持久连接保证了HTTP

(编程训练)再回首,数据结构——二叉树的前序、中序、后序遍历(非递归)

最近在复习数据结构,顺便看看大一的时候写的代码,看完之后比当初有了更加深刻的体会. 希望这些能提供给初学者一些参考. 在VC++6.0下可运行,当初还写了不少注释. 可以和(编程训练)再回首,数据结构--二叉树的前序.中序.后序遍历(递归)对比着看 [问题描述] 根据顺序存储结构建立二叉树的二叉链表,并对二叉树进行先序.中序.后序遍历. [基本要求] ·功能:根据顺序存储结构建立二叉树的二叉链表,并进行先序.中序.后序遍历. ·输入:输入二叉树的顺序存储. ·输出:二叉树的先序.中序.后序遍历序

C语言编程入门——综合练习(四)上机考试题

这份程序是我们学院C语言上机考试题库中的部分题,由我同学总结,并共享给大家.(Word中的程序,排版有些问题,还请见谅) 求n个(项)数据之和或积 //求n个数据的和(或积) #include <stdio.h> int main() { int a[100];  int i = 0; int n; printf("此程序将实现累和还有累积的功能,请输入项数\n"); scanf("%d", &n); printf("请输入各项\n&q

2019.10.24模拟赛赛后总结

本文原创,如果有不到位的地方欢迎通过右下角的按钮私信我! A.Icow Player 题目描述 被无止境的农活压榨得筋疲力尽后,Farmer John打算用他在MP3播放器市场新买的iCow来听些音乐,放松一下.FJ的iCow里存了N(1 <= N <= 1,000)首曲子,按1..N依次编号.至于曲子播放的顺序,则是按一个Farmer John自己设计的算法来决定: * 第i首曲子有一个初始权值R_i(1 <= R_i <= 10,000). * 当一首曲子播放完毕,接下来播放的

两个栈模拟一个队列和两个队列模拟一个栈

此为网易的一道笔试题.到时候秀逗,不知所云.后来研究之后记录下,以备以后经常翻阅. 栈:先进后出 push和pop 队列:先进先出 offer和poll (1)两个栈模拟一个队列 即将先进后出实现先进先出.比较容易理解,只要所有数据先往一个栈里push,然后将该栈中的数据依次pop出来再push进第二个队列,则顺序自然颠倒过来了,则每次pop是从第二个队列中取数据. import java.util.*; public class StackQueue{ private Stack<Intege

C++ 字符串编程训练1

最近又到了找工作的时间,所以想每天抽点时间出来对编程进行相关训练.C++字符串是一个很重要的知识点,采用STL.算法等C++优于C的方面,能够使问题解决起来更加轻松.以下程序都是自己写的,可能有些地方时间效率.空间效率不高,所以希望大家能够多多讨论交流,互相提升. 题目:删除子串 说明:给定两个形参str和substr,其中str为源字符串,substr为需要删除的子串,如果str中包含substr,则将其删除并输出新的字符串,否则输出源字符串. void delete_substr(strin

数据结构和算法之栈和队列一:两个栈模拟一个队列以及两个队列模拟一个栈

今天我们需要学习的是关于数据结构里面经常看到的两种结构,栈和队列.可以说我们是一直都在使用栈,比如说在前面递归所使用的的系统的栈,以及在链表倒序输出时介绍的自定义栈类Stack和使用系统的栈进行递归.那么,在这里我们就讲述一下这两个比较具有特色的或者说关系比较紧密的数据结构之间的互相实现问题. 一:两个栈模拟实现一个队列: 栈的特点是先进后出,然而队列的特点是先进先出. public class Queen(Stack s1,Stack s2){ //实现插入的方法 public void ad