【PAT甲级】1148——1151 9.8秋季考试

考试之前想先耍点小聪明,一直没点开始
先把我的堆优化dj算法敲好了再点开始。
结果点开始之后时间还是给我扣了3分钟。。。醉了醉了

本以为一个小时就能敲好的,结果花了一个小时半,正确率也挺低的。。。
两次段错误,没看清数据范围,加一次没用map,用数组来映射爆了内存。
考前和学长吹我肯定4次提交AK的,啪啪啪打脸了。。
有点不开心

这次考试后面三题都很常规吧,就是看完题目就会做了
这个狼人杀题,因为我之前用搜索做过顶级的那道狼人杀题(虽然是TLE了)
所以看到还是挺慌的,结果是个simple版本
想了挺久才确定写枚举狼人答案的版本
后面三题还是水水的,对树图熟悉就好了
最后一题求lca,正好我最近给学生家教的时候在讲lca,所以写的还是挺熟练的
数据范围不大,我就懒得树上倍增了,就直接O(N)求
不过当时data-》tree*地址的映射,我觉得直接数组哈希过去就行了,没用map
结果姥姥不按常理出牌,直接数据很大,让我段错误+1,mle+1
最后还是乖乖用了map
这里写图片描述

下次顶级见吧~希望到时候也能AK(就目前来看机会还是约等于0的。。除非出的全都是我擅长的数据结构。。)

1148 Werewolf - Simple Version(20 分)
Werewolf(狼人杀) is a game in which the players are partitioned into two parties: the werewolves and the human beings. Suppose that in a game,

player #1 said: “Player #2 is a werewolf.”;
player #2 said: “Player #3 is a human.”;
player #3 said: “Player #4 is a werewolf.”;
player #4 said: “Player #5 is a human.”; and
player #5 said: “Player #4 is a human.”.
Given that there were 2 werewolves among them, at least one but not all the werewolves were lying, and there were exactly 2 liers. Can you point out the werewolves?

Now you are asked to solve a harder version of this problem: given that there were N players, with 2 werewolves among them, at least one but not all the werewolves were lying, and there were exactly 2 liers. You are supposed to point out the werewolves.

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (5≤N≤100). Then N lines follow and the i-th line gives the statement of the i-th player (1≤i≤N), which is represented by the index of the player with a positive sign for a human and a negative sign for a werewolf.

Sample Input 1:
5
-2
+3
-4
+5
+4
Sample Output 1:
1 4
Sample Input 2:
6
+6
+3
+1
-5
-2
+4
Sample Output 2 (the solution is not unique):
1 5
Sample Input 3:
5
-2
-3
-4
-5
-1
Sample Output 3:
No Solution

题意是每个人说一个人是不是狼,正就是民,负就是狼。
一定是两个人说谎,且一定是一人一狼说谎
那么枚举哪两个是狼,再验证这种枚举是不是对的,对的直接输出即可,因为要输出字典序最小的,所以枚举从小到大枚举就行了

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N = (int)1e2+10;
typedef long long ll;
int arr[N];
int cnt1 = 0, cnt2= 0;
int main(void)
{
    int n, m;
    int i, j, k;
    scanf("%d", &n);
    for (i = 1; i <= n; i++)
    {
        scanf("%d", &arr[i]);
    }
    for (i = 1; i <= n; i++)
    {
        for (j = i+1; j <= n; j++)/*i,j分别是两条小狼*/ 
        {
            cnt1 = 0, cnt2 = 0; /*分别是说谎的人和说谎的狼的数量*/ 
            bool flag = true;
            if (i == j) continue;/*其实没必要,考试时脑子不是很清楚,
                                所以下面也有很多是不用写的或是写繁琐了*/ 
            for (k = 1; k <= n; k++)
            {
                if (arr[k] < 0)/*如果他说这个人是狼*/ 
                {
                    if (-arr[k] != i && -arr[k] != j)/*但是这个人却不是狼*/ 
                    {
                        if (k == i || k == j) cnt2++;/*看看这个说谎的人是不是狼*/ 
                        if (cnt2+cnt1 > 2)
                        {
                            flag = false;
                            break;
                        }
                        if (k != i && k != j) cnt1++;/*看看这个说谎的人是不是民*/ 
                        if (cnt1+cnt2 > 2)
                        {
                            flag = false;
                            break;
                        }

                    }
                }
                else 
                {
                    if (arr[k] == i || arr[k] == j)
                    {
                        if (k == i || k == j) cnt2++;
                        if (cnt2+cnt1 > 2)
                        {
                            flag = false;
                            break;
                        }
                        if (k != i && k != j) cnt1++;
                        if (cnt1+cnt2 > 2)
                        {
                            flag = false;
                            break;
                        }

                    }
                }
            }
            if (flag && cnt2 == 1 && cnt1 + cnt2 == 2)/*判断是否满足条件,满足输出即可*/ 
            {
                printf("%d %d", i, j);
                return 0;
            }
        }
    }
    printf("No Solution");
}

1149 Dangerous Goods Packaging(25 分)
When shipping goods with containers, we have to be careful not to pack some incompatible goods into the same container, or we might get ourselves in serious trouble. For example, oxidizing agent (氧化剂) must not be packed with flammable liquid (易燃液体), or it can cause explosion.

Now you are given a long list of incompatible goods, and several lists of goods to be shipped. You are supposed to tell if all the goods in a list can be packed into the same container.

Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers: N (≤10
​4
​​ ), the number of pairs of incompatible goods, and M (≤100), the number of lists of goods to be shipped.

Then two blocks follow. The first block contains N pairs of incompatible goods, each pair occupies a line; and the second one contains M lists of goods to be shipped, each list occupies a line in the following format:

K G[1] G[2] … G[K]
where K (≤1,000) is the number of goods and G[i]’s are the IDs of the goods. To make it simple, each good is represented by a 5-digit ID number. All the numbers in a line are separated by spaces.

Output Specification:
For each shipping list, print in a line Yes if there are no incompatible goods in the list, or No if not.

Sample Input:
6 3
20001 20002
20003 20004
20005 20006
20003 20001
20005 20004
20004 20006
4 00001 20004 00002 20003
5 98823 20002 20003 20006 10010
3 12345 67890 23333
Sample Output:
No
Yes
Yes

水题,我就不分析了哈。

#include <bits/stdc++.h>
using namespace std;
const int N = (int)1e5+10;
typedef long long ll;
int arr[N];
vector<int> g[N];
bool visit[N];
int main(void)
{
    int n, q;
    scanf("%d%d", &n, &q);
    int i, j;
    for (i = 1; i <= n; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    while (q--)
    {
        memset(visit, false, sizeof (visit));
        int k;
        bool flag = true;
        scanf("%d", &k);
        for (i = 1; i <= k; i++)
        {
            int a;
            scanf("%d", &a);
            if (flag == false) continue;
            if (visit[a])
            {
                flag = false;
                continue;
            }
            for (j = 0; j < g[a].size();j++)
            {
                visit[g[a][j]] = true;
            }
        }
        if (flag)
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
}

1150 Travelling Salesman Problem(25 分)
The “travelling salesman problem” asks the following question: “Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city and returns to the origin city?” It is an NP-hard problem in combinatorial optimization, important in operations research and theoretical computer science. (Quoted from “https://en.wikipedia.org/wiki/Travelling_salesman_problem“.)

In this problem, you are supposed to find, from a given list of cycles, the one that is the closest to the solution of a travelling salesman problem.

Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers N (2N≤200), the number of cities, and M, the number of edges in an undirected graph. Then M lines follow, each describes an edge in the format City1 City2 Dist, where the cities are numbered from 1 to N and the distance Dist is positive and is no more than 100. The next line gives a positive integer K which is the number of paths, followed by K lines of paths, each in the format:

where n is the number of cities in the list, and C​i’s are the cities on a path.

Output Specification:
For each path, print in a line Path X: TotalDist (Description) where X is the index (starting from 1) of that path, TotalDist its total distance (if this distance does not exist, output NA instead), and Description is one of the following:

TS simple cycle if it is a simple cycle that visits every city;
TS cycle if it is a cycle that visits every city, but not a simple cycle;
Not a TS cycle if it is NOT a cycle that visits every city.
Finally print in a line Shortest Dist(X) = TotalDist where X is the index of the cycle that is the closest to the solution of a travelling salesman problem, and TotalDist is its total distance. It is guaranteed that such a solution is unique.

Sample Input:
6 10
6 2 1
3 4 1
1 5 1
2 5 1
3 1 8
4 1 6
1 6 1
6 3 1
1 2 1
4 5 1
7
7 5 1 4 3 6 2 5
7 6 1 3 4 5 2 6
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 2 5 4 3 1
7 6 3 2 5 4 1 6
Sample Output:
Path 1: 11 (TS simple cycle)
Path 2: 13 (TS simple cycle)
Path 3: 10 (Not a TS cycle)
Path 4: 8 (TS cycle)
Path 5: 3 (Not a TS cycle)
Path 6: 13 (Not a TS cycle)
Path 7: NA (Not a TS cycle)
Shortest Dist(4) = 8

题意:给你一张图,若干条路径
你去看看每条路径是不是简单环(经过每个点只有一次)
或者复杂环(经过了某些点不止一次)
或者不是环(有些点没去过)
然后再输出这些路径的长度和最短环的大小
有点复杂的模拟,难倒是不难,烦。。。

#include <bits/stdc++.h>
using namespace std;
const int N = (int)2e2+10;
bool visit[N];
typedef long long ll;
int g[N][N];
int main(void)
{
    int n, m, q;
    scanf("%d%d", &n, &m);
    int i, j;
    for (i = 1; i <= m; i++)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        g[a][b] = g[b][a] = c;
    }
    scanf("%d", &q);
    int mi = INT_MAX;
    int ans = 0;
    for (j = 1; j <= q; j++)
    {
        memset(visit, false, sizeof(visit));
        int flag = 0;
        int k, st, ed, now, pre;
        scanf("%d%d", &k, &st);
        pre = st; visit[st] = true;
        int res = 0;
        for (i = 2; i <= k; i++)
        {
            scanf("%d", &now);
            visit[now] = true;
            ed = now;
            if (flag) continue;
            if (!g[pre][now])
            {
                flag = 3; continue;/*没路,说明路径长为NA,continue而不是break
                                    是因为还有数据没scanf*/ 
            }
            res += g[pre][now];
            pre = now;
        }
        if (flag == 3)
        {
            printf("Path %d: NA (Not a TS cycle)\n", j);
            continue;
        }
        printf("Path %d: %d ", j, res);
        bool jt = true;
        for (i = 1; i <= n; i++)/*看看是不是所有点都到过*/ 
        {
            if (!visit[i])
            {
                jt = false;
                break;
            }
        }
        if (jt && k == n+1 && st == ed)/*简单环肯定是n+1个点,首尾相连嘛,所以st=ed*/ 
        {
            printf("(TS simple cycle)");
            if (res < mi)
            {
                ans = j;
                mi = res;
            }
        }
        else if (st != ed || !jt)/*如果收尾没相连或是有些点没去过*/ 
        {
            printf("(Not a TS cycle)");
        }
        else
        {
            printf("(TS cycle)");
            if (res < mi)
            {
                ans = j;
                mi = res;
            }
        }
        printf("\n");
    }
    printf("Shortest Dist(%d) = %d", ans, mi);
}

1151 LCA in a Binary Tree(30 分)
The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

Given any two nodes in a binary tree, you are supposed to find their LCA.

Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.

Output Specification:
For each given pair of U and V, print in a line LCA of U and V is A. if the LCA is found and A is the key. But if A is one of U and V, print X is an ancestor of Y. where X is A and Y is the other node. If U or V is not found in the binary tree, print in a line ERROR: U is not found. or ERROR: V is not found. or ERROR: U and V are not found..

Sample Input:
6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99
Sample Output:
LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

题意:
给前中序,求树
再在树上求lca
n是1e4,q查询是1e3,树上倍增是nlogn+qlogn,直接lca求就是qn
很明显直接qn也不会tle(只有超过1e8才有tle的可能)
这里每个数据唯一,所以可以开个map从数据映射到节点
但是不能用数组,一次sf一次mle告诉我里面有节点data超过1e8的节点
代码:

#include <bits/stdc++.h>
using namespace std;
const int N = (int)1e4+10;
typedef long long ll;
int pre[N], in[N];

struct tree{
    int data;
    tree *left, *right;
    tree(int a)
    {
        data = a;
        left = right = NULL;
    }
};
map<int, tree*> mp;
tree* build(tree* root, int prel, int prer, int inl,int inr)
{
    root = new tree(pre[prel]);
    mp[pre[prel]] = root;
    int i;
    for (i = inl; i <= inr; i++)
    {
        if (in[i] == pre[prel]) break;
    }
    if (i != inl)
    {
        root->left = build(root->left, prel+1, prel+i - inl, inl, i-1);
    }
    if (i != inr)
    {
        root->right = build(root->right, prel+i - inl+1, prer, i+1, inr);
    }
    return root;
}
int cnt = 0;
tree* lca(tree* root, tree* p, tree* q)/*这个我就不解释啦,自己琢磨下吧~*/ 
{
    if (root == p || root == q || !root)
    {
        return root;
    }

    tree* l = lca(root->left, p, q);
    tree* r = lca(root->right, p, q);

    if (l && r)
    {
        cnt = 2; return root;/*标记一下,说明两个人不是祖孙关系,是不同的分支*/ 
    }
    if (l)
    {
     return l;
    }
    else
    {
    return r;
    }
}
int main(void)
{
    int q, n;
    scanf("%d%d", &q, &n);
    int i, j;
    for (i = 1; i <= n; i++)
    {
        scanf("%d", &in[i]);
    }
    for (i = 1; i <= n; i++)
    {
        scanf("%d", &pre[i]);
    }
    tree *root = NULL;
    root = build(root, 1, n, 1, n);
    while (q--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if (!mp[a] || !mp[b])
        {
            if (!mp[a] && !mp[b])
            {
                printf("ERROR: %d and %d are not found.", a, b);
            }
            else if (!mp[a])
            {
                printf("ERROR: %d is not found.", a);
            }
            else
            {
                printf("ERROR: %d is not found.", b);
            }
            printf("\n");
            continue;
        }
        cnt = 0;
        tree* temp = lca(root, mp[a], mp[b]);
        if (!temp)/*一开始段错误我还以为是temp是NULL,所以这里写
                    一个if看看是不是数据有问题,但是报给我的是mle
                    不是sf,说明不是temp的问题*/ 
        {
            cout << "wtf";
        }
        if (cnt == 2)
        {
            printf("LCA of %d and %d is %d.", a, b, temp->data);
        }
        else
        {
            if (temp->data == a)
            {
                printf("%d is an ancestor of %d.",a, b);
            }
            else
            {
                printf("%d is an ancestor of %d.",b, a);
            }
        }
        printf("\n");
    }
}

上面都是考场代码
很多写的杂乱了点
各位有问题可以评论提问哈~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值