1. 程式人生 > >【PAT甲級】1148——1151 9.8秋季考試

【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");
    }
}

上面都是考場程式碼
很多寫的雜亂了點
各位有問題可以評論提問哈~