【刷题-考研上机模拟】概念专题-2019浙大上机模拟(晴神)

3月8日 概念专题

A - 边覆盖

Problem Description

对一个给定的无向图G(V,E),边集E'是E的子集。如果V中的所有顶点都在E'中出现过,那么称边集E'是图G的一个边覆盖(Edge Cover)。
(以上定义引自https://en.wikipedia.org/wiki/Edge_cover

根据上面的定义,请判断一些给定的边集是否是给定的无向图的边覆盖。

Input

每个输入文件一组数据。

第一行为两个整数N、M(1<=N<=500, 1<=M<=N*(N-1)/2),分别表示无向图的顶点数和边数。假设图上的顶点编号为从1到N。

接下来M行,每行两个正整数u、v(1<=u,v<=N, u!=v),分别表示一条无向边的两个端点。数据保证没有重边。

接着一个正整数K(K<=10),表示查询的个数。

然后是K个查询,每个查询第一行为一个正整数L(L<=M),表示欲查询边集E'中的边数;接下来L行,每行两个整数,表示边集E'中的一条边。数据保证E'一定是E的子集。

Output

每个查询一行,如果欲查询边集E'不是图G的边覆盖,那么输出No;否则输出Yes

Sample Input

6 7
1 2
1 3
2 3
2 4
3 5
4 5
4 6
3
3
1 2
3 5
4 6
4
1 2
2 3
4 5
4 6
3
1 2
2 3
4 6

Sample Output

Yes
Yes
No

分析:先判断E‘是否是E'的子集,再判断E'有没有覆盖全部顶点

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<unordered_map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<limits>
using namespace std;
const int nmax = 510;
struct node{
    int u, v;
};
unordered_map<int, bool>mp;
bool vis[nmax] = {false};
int main(){
    #ifdef ONLINE_JUDGE
    #else
    freopen("input.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    int n, m, K, L;
    cin>>n>>m;
    for(int i = 0; i < m; ++i){
        int u, v;
        cin>>u>>v;
        mp[u * nmax + v] = mp[v * nmax + u] = true;
    }
    cin>>K;
    for(int i = 0; i < K; ++i){
        fill(vis, vis + nmax, false);
        bool flag = true;
        cin>>L;
        for(int j = 0; j < L; ++j){
            int u, v;
            cin>>u>>v;
            vis[u] = vis[v] = true;
            if(mp[u * nmax + v] == false)flag = false;
        }
        if(flag == true){
            for(int j = 1; j <= n; ++j){
                if(vis[j] == false){
                    flag = false;
                    break;
                }
            }
        }
        printf("%s
", flag == true ? "Yes" : "No");
    }
    return 0;
}

B - 极大独立集

Problem Description

对一个给定的无向图G(V,E),点集V'是V的子集。如果V'中的任意两个顶点之间都没有边,就称点集V'是图G的独立集(Independent Set)。在此基础上,如果往V'中添加任何一个在V中但不在V'中的顶点,都会使V'变成非独立集,那么就称V'是图G的极大独立集(Maximal Independent Set)。
(以上定义引自https://en.wikipedia.org/wiki/Independentset(graph_theory)

根据上面的定义,请判断一些给定的点集是否是给定的无向图的极大独立集。

Input

每个输入文件一组数据。

第一行为两个整数N、M(1<=N<=500, 1<=M<=N*(N-1)/2),分别表示无向图的顶点数和边数。假设图上的顶点编号为从1到N。

接下来M行,每行两个正整数u、v(1<=u,v<=N, u!=v),分别表示一条无向边的两个端点。数据保证没有重边。

接着一个正整数K(K<=10),表示查询的个数。

然后是K个查询,每个查询第一行为一个正整数L(L<=N),表示欲查询点集V'的顶点个数;第二行为用空格隔开的L个正整数,表示V'中的顶点编号。数据保证V'一定是V的子集。

Output

每个查询一行,如果欲查询的点集不是图G的独立集,那么输出Not an Independent Set;如果欲查询的点集是图G的独立集但不是极大独立集,那么输出Not Maximal;如果欲查询的点集是图G的极大独立集,输出Yes

Sample Input

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

Sample Output

Not Maximal
Yes
Not an Independent Set

分析:先判断集合V'是不是独立集,然后枚举V-V’中的顶点,判断是不是最大独立集,注意枚举时根据是否将V‘中的点全部枚举作为判断是不是最大独立集的条件

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<unordered_map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<limits>
using namespace std;
const int nmax = 510;
unordered_map<int, bool>mp;
bool vis[nmax] = {false};
int main(){
    #ifdef ONLINE_JUDGE
    #else
    freopen("input.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    int n, m, K, L;
    cin>>n>>m;
    for(int i = 0; i < m; ++i){
        int u, v;
        cin>>u>>v;
        mp[u * nmax + v] = mp[v * nmax + u] = true;
    }
    cin>>K;
    for(int i = 0; i < K; ++i){
        fill(vis, vis + nmax, false);
        cin>>L;
        vector<int>v(L);
        for(int j = 0; j < L; ++j){
            cin>>v[j];
            vis[v[j]] = true;
        }
        bool flag1 = true;
        for(int j = 0; j < L; ++j){
            for(int k = j + 1; k < L; ++k){
                if(mp[v[j] * nmax + v[k]] == true){
                    flag1 = false;
                    break;
                }
            }
            if(flag1 == false)break;
        }
        if(flag1 == false){
            printf("Not an Independent Set
");
        }else{
            bool flag2 = true;
            for(int j = 1; j <= n; ++j){
                if(vis[j] == false){
                    int k;
                    for(k = 0; k < L; ++k){
                        if(mp[j * nmax + v[k]] == true)break;
                    }
                    //注意根据k的终值判断
                    if(k == L){
                        flag2 = false;
                        break;
                    }
                }
            }
            printf("%s
", flag2 == true ? "Yes" : "Not Maximal");
        }
    }
    return 0;
}

C - 稳定婚姻问题

Problem Description

有两个点集V1和V2,点集中的顶点个数均为N。现在对V1和V2中的点建立一对一映射关系,也就是说,V1中的每个点对且只对V2中的一个点建立连接关系,V2中的每个点也对且只对V1中的一个点建立连接关系。这样这两个点集间就有N个连接。

已知点集V1中的每个点都对V2中的所有点有一个优先顺序,点集V2中的每个点也对V1中的所有点有一个优先顺序。例如V1中有两个点a1、a2,V2中有两个点b1、b2,那么a1会希望V2中与它连接的点的优先顺序是比如b2 > b1,a2会希望V2中与它相连接的点的优先顺序是比如b1 > b2,b1会希望V1中与它连接的点的优先顺序是比如a1 > a2,b2会希望V1中与它相连接的点的优先顺序是比如a1 > a2。

对给定的一对一映射关系来说,如果存在V1和V2中没有连接关系的一对点(ai, bj),满足(1)对ai来说,bj的优先顺序高于ai当前的连接对象(2)对bj来说,ai的优先顺序也高于bj当前的连接对象,那么我们称这组映射关系是不稳定的;而如果V1和V2中没有连接关系的任意点对(ai, bj)都不满足上面的条件,则称这组映射关系是稳定的。

(以上定义总结自https://en.wikipedia.org/wiki/Stable_marriage_problem

现在给出所有点希望对方点集的点的优先顺序,判断一些映射关系是否是稳定的。

Input

每个输入文件一组数据。

第一行为一个正整数N(N <= 500),表示每个点集中都有N个点。假设每个点集中的点的编号都是从1到N。

接下来N行,每行N个整数,表示点集V1中的点希望V2中与它连接的点的优先顺序。其中第2行为编号为1的点希望V2中与它连接的点的优先顺序,第3行为编号为2的点希望V2中与它连接的点的优先顺序……第N+1行为编号为N的点希望V2中与它连接的点的优先顺序。每行均按优先级从高到低的顺序给出V2中的点的编号。

再接下来N行,每行N个整数,表示点集V2中的点希望V1中与它连接的点的优先顺序。其中第N+2行为编号为1的点希望V1中与它连接的点的优先顺序,第N+3行为编号为2的点希望V1中与它连接的点的优先顺序……第2N+1行为编号为N的点希望V1中与它连接的点的优先顺序。每行均按优先级从高到低的顺序给出V1中的点的编号。

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

每个查询为一组映射关系,共N行,每行两个整数i和j,表示V1中编号为i的点与V2中编号为j的点互为连接对象。数据保证给出的映射关系一定是一对一的。

Output

每行输出一个查询的结果,如果当前查询的映射关系是稳定的,那么输出Stable,否则输出Not Stable

Sample Input

2
2 1
1 2
1 2
1 2
2
1 1
2 2
1 2
2 1

Sample Output

Not Stable
Stable

分析:

1. 题目中需要用到每个点的couple,因此用两个map分别存储,而不选用邻接矩阵

2. 需要查询选择优先级,因此将节点编号作为优先级数组下标,实现对优先级的直接存取

3. 注意题目中的稳定与不稳定是针对每一组映射而言,因此需要枚举点对判断

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<unordered_map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<limits>
using namespace std;
const int nmax = 510;
int p1[nmax][nmax], p2[nmax][nmax];
int main(){
    #ifdef ONLINE_JUDGE
    #else
    freopen("input.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    int N, K, temp;
    cin>>N;
    for(int i = 1; i <= N; ++i){
        for(int j = 1; j <= N; ++j){
            cin>>temp;
            p1[i][temp] = j;
        }
    }
    for(int i = 1; i <= N; ++i){
        for(int j = 1; j <= N; ++j){
            cin>>temp;
            p2[i][temp] = j;
        }
    }
    cin>>K;
    for(int i = 0; i < K; ++i){
        unordered_map<int, int>mp1, mp2;
        for(int j = 0; j < N; ++j){
            int u, v;
            cin>>u>>v;
            mp1[u] = v;
            mp2[v] = u;
        }
        bool flag = true;
        for(int j = 1; j <= N; ++j){
            for(int k = 1; k <= N; ++k){
                if(mp1[j] != k && mp2[k] != j){
                    int cp1 = mp1[j], cp2 = mp2[k];
                    bool flag1 = p1[j][k] < p1[j][cp1];
                    bool flag2 = p2[k][j] < p2[k][cp2];
                    if((flag1 & flag2) == true){
                        flag = false;
                        break;
                    }
                }
            }
        }
        printf("%s
", flag == true ? "Stable" : "Not Stable");
    }
    return 0;
}

D - 笛卡尔树

Problem Description

对一棵二叉树来说,如果树上的每个结点有两个值K、V,满足
(1)以K为视角时这棵二叉树满足二叉查找树的性质,即对每个结点,左子树所有结点的K值小于该结点的K值小于右子树所有结点的K值;
(2)以V为视角时这棵二叉树满足堆的性质,即每个结点的V值都大于子树所有结点的V值(或都小于子树所有结点的V值)。
那么就称这棵二叉树是笛卡尔树。

(以上定义引自https://en.wikipedia.org/wiki/Cartesian_tree

现在给定一棵二叉树,请判断其是否是笛卡尔树。

注意,笛卡尔树只是满足堆的性质,不代表一定是完全二叉树。

Input

每个输入文件一组数据。

第一行为一个正整数N(2<=N<=1024),表示二叉树上的结点数目。假设结点编号为从1到N。

第二行为N个正整数,表示1到N号结点的K值。数据保证每个值唯一,且不超过10000。

第三行为N个正整数,表示1到N号结点的V值。数据保证每个值唯一,且不超过10000。

接下来N行,按编号从1号到N号的顺序给出每个结点的子结点信息。每行两个整数,分别表示当前结点的左结点编号和右结点编号。如果左结点或右结点为空,则记为-1。

Output

如果该二叉树是笛卡尔树,那么输出第一行YES,然后在第二行输出MIN HEAP或者MAX HEAP,分别表示该笛卡尔树的V值满足小顶堆或大顶堆的性质。

如果该二叉树不是笛卡尔树,那么输出第一行NO,然后在第二行输出错误信息,即如果K值不满足二叉查找树的性质,那么输出NOT BST;如果V值不满足堆的性质,那么输出NOT HEAP;如果K值和V值都不满足,那么输出NOT BST AND NOT HEAP

Sample Input 1

5
6 3 8 1 4
2 5 3 9 8
2 3
4 5
-1 -1
-1 -1
-1 -1

Sample Output 1

YES
MIN HEAP

Sample Input 2

5
6 7 8 1 4
2 5 3 9 8
2 3
4 5
-1 -1
-1 -1
-1 -1

Sample Output 2

NO
NOT BST

Sample Input 3

5
6 3 8 1 4
6 5 3 9 8
2 3
4 5
-1 -1
-1 -1
-1 -1

Sample Output 3

NO
NOT HEAP

Sample Input 4

5
6 7 8 1 4
6 5 3 9 8
2 3
4 5
-1 -1
-1 -1
-1 -1

Sample Output 4

NO
NOT BST AND NOT HEAP

分析:树的递归操作
更正:判断是否为bst时不能根据子树都是bst并且子树根节点和原树根节点满足大小关系判断,因为bst的根节点不是该树中值最大的节点

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<unordered_map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<limits>
using namespace std;
const int nmax = 1100;
struct node{
    int lchild, rchild;
};
node tree[nmax];
int kval[nmax], vval[nmax];
bool vis[nmax] = {false};
//bst
vector<int>inpath;
void inOrder(int root){
    if(root == -1)return;
    inOrder(tree[root].lchild);
    inpath.push_back(kval[root]);
    inOrder(tree[root].rchild);
}
bool isbst(int root){
    if(root == -1)return true;
    inOrder(root);
    bool flag = true;
    for(int i = 1; i < inpath.size(); ++i){
        if(inpath[i] <= inpath[i - 1]){
            flag = false;
            break;
        }
    }
    return flag;
}
//bool isbst(int root){
//    if(root == -1)return true;
//    int l = tree[root].lchild, r = tree[root].rchild;
//    if(l == -1 && r == -1)return true;
//    if(l != -1 && r == -1 && kval[l] < kval[root])return true;
//    if(l == -1 && r != -1 && kval[root] < kval[r])return true;
//    if(kval[l] >= kval[root] || kval[root] >= kval[r])return false;
//    return isbst(l) && isbst(r);
//
//}
bool isminheap(int root){
    if(root == -1)return true;
    int l = tree[root].lchild, r = tree[root].rchild;
    if(l == -1 && r == -1)return true;
    if(l != -1 && vval[root] >= vval[l])return false;
    if(r != -1 && vval[root] >= vval[r])return false;
    return isminheap(l) && isminheap(r);
}
bool ismaxheap(int root){
    if(root == -1)return true;
    int l = tree[root].lchild, r = tree[root].rchild;
    if(l == -1 && r == -1)return true;
    if(l != -1 && vval[root] <= vval[l])return false;
    if(r != -1 && vval[root] <= vval[r])return false;
    return ismaxheap(l) && ismaxheap(r);
}
int main(){
    #ifdef ONLINE_JUDGE
    #else
    freopen("input.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    int n;
    cin>>n;
    for(int i = 1; i <= n; ++i)cin>>kval[i];
    for(int i = 1; i <= n; ++i)cin>>vval[i];
    for(int i = 1; i <= n; ++i){
        int u, v;
        cin>>u>>v;
        tree[i].lchild = u;
        tree[i].rchild = v;
        if(u != -1)vis[u] = true;
        if(v != -1)vis[v] = true;
    }
    int root = 1;
    for(int i = 1; i <= n; ++i){
        if(vis[i] == false){
            root = i;
            break;
        }
    }
    bool flag1 = isbst(root);
    bool flag2 = ismaxheap(root);
    bool flag3 = isminheap(root);
    if(flag1 & (flag2 | flag3)){
        printf("YES
");
        if(flag2)printf("MAX HEAP
");
        else printf("MIN HEAP
");
    }else{
        printf("NO
");
        if((flag2 | flag3) == true)printf("NOT BST
");
        else if(flag1 == true)printf("NOT HEAP
");
        else printf("NOT BST AND NOT HEAP
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/vinnson/p/10845029.html