數據結構---樹


二叉樹

還原二叉樹   (25分)

給定一棵二叉樹的先序遍歷序列和中序遍歷序列,要求計算該二叉樹的高度。

輸入格式:

輸入首先給出正整數N(≤\le50),爲樹中結點總數。下面兩行先後給出先序和中序遍歷序列,均是長度爲N的不包含重複英文字母(區別大小寫)的字符串。

輸出格式:

輸出爲一個整數,即該二叉樹的高度。

輸入樣例:

9
ABDFGHIEC
FDHGIBEAC

輸出樣例:

5

解題思路:

本題需要了解樹的先序遍歷和中序遍歷的特點,即樹中的每個節點在各遍歷中的位置規律。

更具此規律,將樹構造出來,然後對復原的樹求高度。

此處的代碼將兩步縮減爲一步,直接求樹高啦。

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 54;
char DLR[MAXN];
char LDR[MAXN];
int Index = 0;
int GetHigth(int l, int r);//在中序序列中確定左右界限,保證該界限內是一棵子樹
int main()
{
    int n;
    scanf("%d", &n);
    getchar();//讀取一個回車
    for(int i = 0; i < n; ++i)
        scanf("%c", &DLR[i]);
    getchar();
    for(int i = 0; i < n; ++i)
        scanf("%c", &LDR[i]);
    printf("%d\n",GetHigth(0, n));
    return 0;
}
int GetHigth(int l, int r)
{
    int h1 = 0, h2 = 0;//定義左右子樹高度
    for(int i = l; i < r; ++i)
    {
        if(DLR[Index] == LDR[i])
        {
            Index++;//在先序序列中,父結點在前,如果在中序序列中找到相同節點,則在中序序列中尋找先序序列中的後一個元素
            h1 = GetHigth(l, i) + 1;//在當前父結點下求左子樹樹高
            h2 = GetHigth(i + 1, r) + 1;//在當前父結點下求右子樹樹高
        }
    }
    return h1 > h2? h1: h2;//返回較高的子樹
}

樹的同構   (25分)

給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因爲我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。


圖1


圖2

現給定兩棵樹,請你判斷它們是否是同構的。

輸入格式:

輸入給出2棵二叉樹樹的信息。對於每棵樹,首先在一行中給出一個非負整數NNN (≤10\le 1010),即該樹的結點數(此時假設結點從0到N−1N-1N1編號);隨後NNN行,第iii行對應編號第iii個結點,給出該結點中存儲的1個英文大寫字母、其左孩子結點的編號、右孩子結點的編號。如果孩子結點爲空,則在相應位置上給出“-”。給出的數據間用一個空格分隔。注意:題目保證每個結點中存儲的字母是不同的。

輸出格式:

如果兩棵樹是同構的,輸出“Yes”,否則輸出“No”。

輸入樣例1(對應圖1):

8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -

輸出樣例1:

Yes

輸入樣例2(對應圖2):

8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -
H - -
C 0 2
G - 3
F - -
A 1 4

輸出樣例2:

No

解題思路:

1)利用樹狀結構存儲數據,採用結構體存儲

2)使用層次遍歷,判斷是否同構

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 12;
struct node{
    char data, lc, rc;
}Node1[MAXN], Node2[MAXN], Order1[MAXN], Order2[MAXN];//定義存儲結構
bool isRoot1[MAXN], isRoot2[MAXN];//判斷是否爲根結點

int main()
{
    int n1 = 0, n2 = 0, f = 0, e = 0;
    int root1 = 0, root2 = 0;
    bool Yes = true;
    cin>>n1;
    for(int i = 0; i < n1; ++i)
        isRoot1[i] = true;
    for(int i = 0; i < n1; ++i)//讀入數據並判斷是否爲根結點
    {
        cin>>Node1[i].data>>Node1[i].lc>>Node1[i].rc;
        if(Node1[i].lc != '-') isRoot1[Node1[i].lc - '0'] = false;
        if(Node1[i].rc != '-') isRoot1[Node1[i].rc - '0'] = false;
    }
    for(int i = 0; i < n1; ++i)//得到根結點
        if(isRoot1[i]) root1 = i;
    Order1[e++] = Node1[root1];//進行層序遍歷結果
    while(e < n1)
    {
        struct node tmp = Order1[f++];
        if(tmp.lc != '-') Order1[e++] = Node1[tmp.lc - '0'];
        if(tmp.rc != '-') Order1[e++] = Node1[tmp.rc - '0'];
    }
    f = 0, e = 0;//第二個數據信息,同樣處理,但是層次遍歷時,左右子樹顛倒
    cin>>n2;
    for(int i = 0; i < n2; ++i)
        isRoot2[i] = true;
    for(int i = 0; i < n2; ++i)
    {
        cin>>Node2[i].data>>Node2[i].lc>>Node2[i].rc;
        if(Node2[i].lc != '-') isRoot2[Node2[i].lc - '0'] = false;
        if(Node2[i].rc != '-') isRoot2[Node2[i].rc - '0'] = false;
    }
    for(int i = 0; i < n2; ++i)
        if(isRoot2[i]) root2= i;
    Order2[e++] = Node2[root2];
    while(e < n2)
    {
        struct node tmp = Order2[f++];
        if(tmp.rc != '-') Order2[e++] = Node2[tmp.rc - '0'];
        if(tmp.lc != '-') Order2[e++] = Node2[tmp.lc - '0'];
    }
    if(n1 == n2)//如果兩者節點總數相同,則判斷是否同一遍歷順序
    {
        for(int i = 0; i < n1 && Yes; ++i)
        {
            if(Order1[i].data != Order2[i].data) Yes = false;
        }
    }
    else Yes = false;
    if(Yes) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;
}

List Leaves   (25分)

Given a tree, you are supposed to list all the leaves in the order of top down, and left to right.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integerNNN (≤10\le 1010) which is the total number of nodes in the tree -- and hence the nodes are numbered from 0 toN−1N-1N1. Then NNN lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a "-" will be put at the position. Any pair of children are separated by a space.

Output Specification:

For each test case, print in one line all the leaves' indices in the order of top down, and left to right. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.

Sample Input:

8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6

Sample Output:

4 1 5

解題思路:

本題建樹後,考慮做層次遍歷,遍歷同時將葉節點輸出即可

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 12;
struct infi{
    int data,lc, rc;
}node[MAXN], tmp, q[MAXN];//樹結點
bool isroot[MAXN];

int main()
{
    int n;
    char ch1, ch2;
    int f = 0, e = 0;
    cin>>n;
    for(int i = 0; i < n; ++i)//讀入輸入信息
    {
        cin>>ch1>>ch2;
        node[i].data = i;
        if(ch1 != '-') node[i].lc = ch1 - '0', isroot[ch1 - '0'] = true;
        else node[i].lc = -1;
        if(ch2 != '-') node[i].rc = ch2 - '0', isroot[ch2 - '0'] = true;
        else node[i].rc = -1;
    }
    int root = 0, cnt = 0;
    for(root = 0; isroot[root]; ++root) ; //循環體爲空的for語句,尋找根結點
    q[e++] = node[root];//層次遍歷
    while(f < e)
    {
        tmp = q[f++];
        if(tmp.lc != -1) q[e++] = node[tmp.lc];
        if(tmp.rc != -1) q[e++] = node[tmp.rc];
        if(tmp.lc == -1 && tmp.rc == -1)//將葉結點輸出
        {
            if(cnt) cout<<' ';
            cout<<tmp.data;
            cnt++;
        }
    }
    return 0;
}

Tree Traversals Again   (25分)

An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.


Figure 1

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integerNNN (≤30\le 3030) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 toNNN). Then 2N2N2N lines follow, each describes a stack operation in the format: "Push X" where X is the index of the node being pushed onto the stack; or "Pop" meaning to pop one node from the stack.

Output Specification:

For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop

Sample Output:

3 4 2 6 5 1

解題思路:

題意是將堆棧的操作可以建立二叉樹,再將對二叉樹後序遍歷輸出

堆棧的操作看似麻煩,對照題中的例子可以發現,題中所謂的堆棧操作實則前序遍歷。

因此可以使用前序遍歷的方式建樹

建完之後,後序輸出便是。

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
typedef struct TNode tnode;
struct TNode{
    int data;
    tnode *lc, *rc;
};
int cnt = 0;//紀錄堆棧操作數
tnode *Create(int n);//建立含有n個結點的樹
void posttra(tnode *bt);//後序遍歷
int main()
{
    int n;
    cin>>n;
    tnode *bt = Create(n);
    cnt = 0;
    posttra(bt);
    return 0;
}
tnode *Create(int n)
{
    string str = "";
    tnode *t = NULL;
    cin>>str;
    if(str == "Push")//如果是進棧,那麼作爲樹結點
    {
        t = new tnode;
        cin>>t->data;
        t->lc = Create(n);
        t->rc = Create(n);
    }
    return t;
}
void posttra(tnode *bt)
{
    if(bt)
    {
        posttra(bt->lc);
        posttra(bt->rc);
        if(cnt) cout<<' ';
        cout<<bt->data;
        cnt++;
    }
}


二叉搜索樹

是否同一棵二叉搜索樹   (25分)

給定一個插入序列就可以唯一確定一棵二叉搜索樹。然而,一棵給定的二叉搜索樹卻可以由多種不同的插入序列得到。例如分別按照序列{2, 1, 3}和{2, 3, 1}插入初始爲空的二叉搜索樹,都得到一樣的結果。於是對於輸入的各種插入序列,你需要判斷它們是否能生成一樣的二叉搜索樹。

輸入格式:

輸入包含若干組測試數據。每組數據的第1行給出兩個正整數NNN (≤10\le 1010)和LLL,分別是每個序列插入元素的個數和需要檢查的序列個數。第2行給出NNN個以空格分隔的正整數,作爲初始插入序列。最後LLL行,每行給出NNN個插入的元素,屬於LLL個需要檢查的序列。

簡單起見,我們保證每個插入序列都是1到NNN的一個排列。當讀到NNN爲0時,標誌輸入結束,這組數據不要處理。

輸出格式:

對每一組需要檢查的序列,如果其生成的二叉搜索樹跟對應的初始序列生成的一樣,輸出“Yes”,否則輸出“No”。

輸入樣例:

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

輸出樣例:

Yes
No
No

解題思路:

本題先要建立二叉搜索樹,之後進行遍歷操作,然後比較兩個樹是否一致。

其中的遍歷操作此處使用的是層次遍歷,其他的遍歷未嘗試。

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 12;
typedef struct Tnode tnode;
struct Tnode{
    int data;
    tnode *lc, *rc;
};
tnode *Create(int n);//建立n個結點的樹
tnode *Gettree(tnode *t, int Data);
bool issimlar(tnode *T, tnode *xT, int n);//判斷是否是同一個二叉搜索樹
int main()
{
    int n, l;
    while(cin>>n, n)
    {
        cin>>l;
        tnode *T = Create(n);
        for(int i = 0; i < l; ++i)
        {
            tnode *xT = Create(n);
            if(issimlar(T, xT, n)) cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
        }
    }
    return 0;
}
tnode *Create(int n)
{
    tnode *t = NULL;
    int Data;
    for(int i = 0; i < n; ++i)
    {
        cin>>Data;
        t = Gettree(t, Data);
    }
    return t;
}
tnode *Gettree(tnode *t, int Data)
{
    if(t == NULL)//如果沒有這個值,則建立新結點存儲
    {
        tnode *tmpt = new tnode;
        tmpt->data = Data;
        tmpt->lc = tmpt->rc = NULL;
        t = tmpt;
    }
    else if(t->data > Data)//如果小於當前結點值,則存儲於左子樹
    {
        t->lc = Gettree(t->lc, Data);
    }
    else if(t->data < Data)//如果大於當前結點值,則存儲於右子樹
    {
        t->rc = Gettree(t->rc, Data);
    }
    return t;
}
bool issimlar(tnode *T, tnode *xT, int n)
{
    bool falg = true;
    tnode *q1[MAXN], *q2[MAXN], *t1 = T, *t2 = xT;
    int f1 = 0, e1 = 0, f2 = 0, e2 = 0;
    q1[e1++] = t1;
    q2[e2++] = t2;
    while(falg && f1 < e1 && f2 < e2)
    {
        t1 = q1[f1++], t2 = q2[f2++];
        if(t1->data != t2->data) falg = false;//如果當前的值不同,則返回不一致
        else
        {
            if(t1->lc) q1[e1++] = t1->lc;
            if(t1->rc) q1[e1++] = t1->rc;
            
            if(t2->lc) q2[e2++] = t2->lc;
            if(t2->rc) q2[e2++] = t2->rc;
        }
    }
    return falg;
}

樹種統計   (25分)

隨着衛星成像技術的應用,自然資源研究機構可以識別每一棵樹的種類。請編寫程序幫助研究人員統計每種樹的數量,計算每種樹佔總數的百分比。

輸入格式:

輸入首先給出正整數N(≤105\le 10^5105),隨後N行,每行給出衛星觀測到的一棵樹的種類名稱。種類名稱由不超過30個英文字母和空格組成(大小寫不區分)。

輸出格式:

按字典序遞增輸出各種樹的種類名稱及其所佔總數的百分比,其間以空格分隔,保留小數點後4位。

輸入樣例:

29
Red Alder
Ash
Aspen
Basswood
Ash
Beech
Yellow Birch
Ash
Cherry
Cottonwood
Ash
Cypress
Red Elm
Gum
Hackberry
White Oak
Hickory
Pecan
Hard Maple
White Oak
Soft Maple
Red Oak
Red Oak
White Oak
Poplan
Sassafras
Sycamore
Black Walnut
Willow

輸出樣例:

Ash 13.7931%
Aspen 3.4483%
Basswood 3.4483%
Beech 3.4483%
Black Walnut 3.4483%
Cherry 3.4483%
Cottonwood 3.4483%
Cypress 3.4483%
Gum 3.4483%
Hackberry 3.4483%
Hard Maple 3.4483%
Hickory 3.4483%
Pecan 3.4483%
Poplan 3.4483%
Red Alder 3.4483%
Red Elm 3.4483%
Red Oak 6.8966%
Sassafras 3.4483%
Soft Maple 3.4483%
Sycamore 3.4483%
White Oak 10.3448%
Willow 3.4483%
Yellow Birch 3.4483%

解題思路:

本題一個是建立二叉搜索樹,同時做好統計工作。

之後利用二叉搜索樹的特性——中序遍歷得到的序列即能得到有序序列

提交代碼:

編譯器:g++

#include <iostream>
#include <string.h>
using namespace std;
struct Tnode{
    char str[33];
    int cnt;
    struct Tnode *lc, *rc;
};
struct Tnode *buildTree(struct Tnode *t, char *str);
void LDR(struct Tnode *t, int n);
int main()
{
    int n;
    char str[33], ch;
    Tnode *t = NULL;
    scanf("%d", &n);
    getchar();
    for(int i = 0, j = 0; i < n; ++i)//輸入n個元素的值
    {
        while((ch = getchar()) != '\n')
            str[j++] = ch;
        str[j] = 0, j = 0;
        t = buildTree(t, str);
    }
    LDR(t, n);
    return 0;
}
struct Tnode *buildTree(struct Tnode *t, char *str)
{
    if(t == NULL)
    {
        t = new struct Tnode;
        t->cnt = 1;
        t->lc = t->rc = NULL;
        strcpy(t->str, str);
    }
    else if(strcmp(t->str, str) > 0)
        t->lc = buildTree(t->lc, str);
    else if(strcmp(t->str, str) < 0)
        t->rc = buildTree(t->rc, str);
    else   //當讀到相同的元素時,計數器累加
        t->cnt++;
    return t;
}
void LDR(struct Tnode *t, int n)//中序遍歷輸出,注意百分號的輸出格式
{
    if(t)
    {
        LDR(t->lc, n);
        printf("%s %.4lf%%\n", t->str, 100.0 * t->cnt / n);
        LDR(t->rc, n);
    }
}

搜索樹判斷   (25分)

對於二叉搜索樹,我們規定任一結點的左子樹僅包含嚴格小於該結點的鍵值,而其右子樹包含大於或等於該結點的鍵值。如果我們交換每個節點的左子樹和右子樹,得到的樹叫做鏡像二叉搜索樹。

現在我們給出一個整數鍵值序列,請編寫程序判斷該序列是否爲某棵二叉搜索樹或某鏡像二叉搜索樹的前序遍歷序列,如果是,則輸出對應二叉樹的後序遍歷序列。

輸入格式:

輸入的第一行包含一個正整數N(≤\le1000),第二行包含N個整數,爲給出的整數鍵值序列,數字間以空格分隔。

輸出格式:

輸出的第一行首先給出判斷結果,如果輸入的序列是某棵二叉搜索樹或某鏡像二叉搜索樹的前序遍歷序列,則輸出YES,否側輸出NO。如果判斷結果是YES,下一行輸出對應二叉樹的後序遍歷序列。數字間以空格分隔,但行尾不能有多餘的空格。

輸入樣例1:

7
8 6 5 7 10 8 11

輸出樣例1:

YES
5 7 6 8 11 10 8

輸入樣例2:

7
8 6 8 5 10 9 11

輸出樣例2:

NO

解題思路:

1)本題需要建二叉搜索樹

2)對該樹進行先序遍歷,如果先序遍歷結果與輸入數據相同,則後序遍歷該樹結束;否則進入3)

3)先對建的樹轉化爲鏡像,然後執行先序遍歷,如果與輸入數據相同,則後序遍歷該樹結束;否則輸出NO

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 1002;
struct Tnode{
    int num;
    struct Tnode *lc, *rc;
};
int num[MAXN], DLRnum[MAXN], Index = 0;
struct Tnode *buildTree(struct Tnode *t, int num); //建樹
void DLR(struct Tnode *t); //前序遍歷
void LRD1(struct Tnode *t); //後序遍歷
void LRD2(struct Tnode *t); //對鏡像後序遍歷
void exChange(struct Tnode *t); //將樹轉換爲鏡像
bool issimial(int n); //判斷是否是前序遍歷或鏡像的前序遍歷
int main()
{
    int n;
    Tnode *t = NULL;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
    {
        scanf("%d", &num[i]);
        t = buildTree(t, num[i]);
    }
    DLR(t);
    if(issimial(n))
    {
        Index = n;
        printf("YES\n");
        LRD1(t);
    }
    else
    {
        Index = 0;
        exChange(t);
        if(issimial(n))
        {
            Index = n;
            printf("YES\n");
            LRD2(t);
        }
        else printf("NO\n");
    }
    return 0;
}
struct Tnode *buildTree(struct Tnode *t, int num)
{
    if(t == NULL)
    {
        t = new struct Tnode;
        t->lc = t->rc = NULL;
        t->num = num;
    }
    else if(t->num > num)
        t->lc = buildTree(t->lc, num);
    else
        t->rc = buildTree(t->rc, num);
    return t;
}
void DLR(struct Tnode *t)
{
    if(t)
    {
        DLRnum[Index++] = t->num;
        DLR(t->lc);
        DLR(t->rc);
    }
}
void LRD1(struct Tnode *t)
{
    if(t)
    {
        LRD1(t->lc);
        LRD1(t->rc);
        printf("%d", t->num);
        Index--;
        if(Index > 0)
            printf(" ");
    }
}
void LRD2(struct Tnode *t)
{
    if(t)
    {
        LRD2(t->rc);
        LRD2(t->lc);
        printf("%d", t->num);
        Index--;
        if(Index > 0)
            printf(" ");
    }
}
void exChange(struct Tnode *t)
{
    if(t)
    {
        DLRnum[Index++] = t->num;
        exChange(t->rc);//只要將訪問左右子樹的順序調換就可以,生成鏡像
        exChange(t->lc);
    }
}
bool issimial(int n)
{
    for(int i = 0; i < n; ++i)
        if(num[i] != DLRnum[i])
            return false;
    return true;
}

笛卡爾樹   (25分)

笛卡爾樹是一種特殊的二叉樹,其結點包含兩個關鍵字K1和K2。首先笛卡爾樹是關於K1的二叉搜索樹,即結點左子樹的所有K1值都比該結點的K1值小,右子樹則大。其次所有結點的K2關鍵字滿足優先隊列(不妨設爲最小堆)的順序要求,即該結點的K2值比其子樹中所有結點的K2值小。給定一棵二叉樹,請判斷該樹是否笛卡爾樹。

輸入格式:

輸入首先給出正整數N(≤\le1000),爲樹中結點的個數。隨後N行,每行給出一個結點的信息,包括:結點的K1值、K2值、左孩子結點編號、右孩子結點編號。設結點從0~(N-1)順序編號。若某結點不存在孩子結點,則該位置給出−1-11

輸出格式:

輸出YES如果該樹是一棵笛卡爾樹;否則輸出NO

輸入樣例1:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 21 -1 4
15 22 -1 -1
5 35 -1 -1

輸出樣例1:

YES

輸入樣例2:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 11 -1 4
15 22 -1 -1
50 35 -1 -1

輸出樣例2:

NO

解題思路:

根據題中所定義的笛卡爾樹,對所給的信息進行建樹

優先判斷是否具有二叉搜索樹的性質

然後再判斷是否具有最小堆的性質

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 1002;
struct infi{
    int k1, k2;
    int lc, rc;
}node[MAXN];
int LDRnum[MAXN];
void LDR(int root, int &index); //中序遍歷得到中序序列
bool isBST(int n); //判斷是否是二叉搜索樹
bool DDD(int index); //判斷是否具有堆的性質
int FindRoot(int n); //找根結點
int main()
{
    int n, index = 0;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
        scanf("%d%d%d%d", &node[i].k1, &node[i].k2, &node[i].lc, &node[i].rc);
    int root = FindRoot(n);
    LDR(root, index);
    if(isBST(n))
    {
        if(DDD(root))
            printf("YES\n");
        else
            printf("NO\n");
    }
    else
        printf("NO\n");
    return 0;
}
void LDR(int root, int &index)
{
    if(node[root].lc != -1)
        LDR(node[root].lc, index);
    LDRnum[index++] = node[root].k1;
    if(node[root].rc != -1)
        LDR(node[root].rc, index);
}
bool isBST(int n)//通過對中序序列判斷是否有序,判斷是否具有二叉搜索樹性質
{
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < i; ++j)
            if(LDRnum[i] < LDRnum[j])
                return false;
    return true;
}
bool DDD(int index)//通過層次遍歷,判斷是否有序。如無序,則不具有最小堆性質
{
    struct infi q[MAXN], tmp;
    int f = 0, e = 0;
    bool islaw = true;
    q[e++] = node[index];
    while(f < e && islaw)
    {
        tmp = q[f++];
        if(tmp.lc != -1)
        {
            if(tmp.k2 >= node[tmp.lc].k2)
                islaw = false;
            else
                q[e++] = node[tmp.lc];
        }
        if(tmp.rc != -1)
        {
            if(tmp.k2 >= node[tmp.rc].k2)
                islaw = false;
            else
                q[e++] = node[tmp.rc];
        }
    }
    return islaw;
}
int FindRoot(int n)
{
    int index = 0;
    bool haveroot[MAXN] = {false};
    for(int i = 0; i < n; ++i)
    {
        if(node[i].lc != -1) haveroot[node[i].lc] = true;
        if(node[i].rc != -1) haveroot[node[i].rc] = true;
    }
    for(int i = 0; i < MAXN; ++i)
        if(!haveroot[i])
        {
            index = i;
            break;
        }
    return index;
}


平衡二叉樹

Root of AVL Tree   (25分)

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.

Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integerNNN (≤20\le 2020) which is the total number of keys to be inserted. Then NNN distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the root of the resulting AVL tree in one line.

Sample Input 1:

5
88 70 61 96 120

Sample Output 1:

70

Sample Input 2:

7
88 70 61 96 120 90 65

Sample Output 2:

88

此處直接參考陳越姥姥網易雲課堂的平衡二叉樹代碼

#include <stdlib.h>
#include <stdio.h>
typedef struct AVLTreeNode *AVLTree;
struct AVLTreeNode{
	int Data;
	AVLTree Left;
	AVLTree Right;
	int Height;
};
int Max(int a, int b)
{
	return a > b? a: b;
}
int GetHeight(AVLTree T)
{
	if(!T) return 0;
	else return T->Height;
}
AVLTree SingleLeftRotation(AVLTree A)
{
	AVLTree B = A->Left;
	A->Left = B->Right;
	B->Right = A;
	A->Height = Max(GetHeight(A->Left), GetHeight(A->Right)) + 1;
	B->Height = Max(GetHeight(B->Left), A->Height) + 1;
	return B;
}
AVLTree SingleRightRotation(AVLTree A)
{
	AVLTree B = A->Right;
	A->Right = B->Left;
	B->Left = A;
	A->Height = Max(GetHeight(A->Left), GetHeight(A->Right)) + 1;
	B->Height = Max(GetHeight(B->Right), A->Height) + 1;
	return B;
}
AVLTree DoubleLeftRightRotation(AVLTree A)
{
	A->Left = SingleRightRotation(A->Left);
	return SingleLeftRotation(A);
}
AVLTree DoubleRightLeftRotation(AVLTree A)
{
	A->Right = SingleLeftRotation(A->Right);
	return SingleRightRotation(A);
}
AVLTree AVL_Insertion(int X, AVLTree T)
{
	if(!T)
	{
		T = (AVLTree)malloc(sizeof(struct AVLTreeNode));
		T->Data = X;
		T->Height = 0;
		T->Left = T->Right = NULL;
	}
	else if(X < T->Data)
	{
		T->Left = AVL_Insertion(X, T->Left);
		if(GetHeight(T->Left) - GetHeight(T->Right) == 2)
		{
			if(X < T->Left->Data) T = SingleLeftRotation(T);
			else T = DoubleLeftRightRotation(T);
		}
	}
	else if(X > T->Data)
	{
		T->Right = AVL_Insertion(X, T->Right);
		if(GetHeight(T->Left) - GetHeight(T->Right) == -2)
		{
			if(X > T->Right->Data)  T = SingleRightRotation(T);
			else T = DoubleRightLeftRotation(T);
		}
	}
	T->Height = Max(GetHeight(T->Left), GetHeight(T->Right)) + 1;
}
int main()
{
	int NodeNum, tmpkey;
	AVLTree tree = NULL;
	scanf("%d", &NodeNum);
	for(int i = 0; i < NodeNum; ++i)
	{
		scanf("%d", &tmpkey);
		tree = AVL_Insertion(tmpkey, tree);
	}
	printf("%d\n", tree->Data);
	return 0;
} 


哈夫曼樹

修理牧場   (25分)

農夫要修理牧場的一段柵欄,他測量了柵欄,發現需要NNN塊木頭,每塊木頭長度爲整數LiL_iLi個長度單位,於是他購買了一條很長的、能鋸成NNN塊的木頭,即該木頭的長度是LiL_iLi的總和。

但是農夫自己沒有鋸子,請人鋸木的酬金跟這段木頭的長度成正比。爲簡單起見,不妨就設酬金等於所鋸木頭的長度。例如,要將長度爲20的木頭鋸成長度爲8、7和5的三段,第一次鋸木頭花費20,將木頭鋸成12和8;第二次鋸木頭花費12,將長度爲12的木頭鋸成7和5,總花費爲32。如果第一次將木頭鋸成15和5,則第二次鋸木頭花費15,總花費爲35(大於32)。

請編寫程序幫助農夫計算將木頭鋸成NNN塊的最少花費。

輸入格式:

輸入首先給出正整數NNN≤104\le 10^4104),表示要將木頭鋸成NNN塊。第二行給出NNN個正整數(≤50\le 5050),表示每段木塊的長度。

輸出格式:

輸出一個整數,即將木頭鋸成NNN塊的最少花費。

輸入樣例:

8
4 5 1 2 1 3 1 1

輸出樣例:

49

解題思路:

本題中所給的輸入數據是已經切完的木塊,也就是一塊木頭將切過之後所得到的木塊

也就是對所給的數據按題中所描述的例子進行逆操作。

該逆操作利用貪心策略,具體是哈夫曼樹解決的。

這裏並沒有建樹,只是利用最小堆做貪心操作(對於堆的知識此處略有欠缺)

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 10002;
int Hcode[MAXN];
void buildHeap(int n); //建立最小堆
void adjustHeap(int index, int n); //調整堆
int PopHeap(int &n); //將最小堆的最小元素彈出
void InsertHeap(int x, int &n); //將元素插入到最小隊中
int main()
{
    int n, index, ans = 0;
    scanf("%d", &n);
    index = n;
    for(int i = 1; i <= n; ++i)
        scanf("%d", &Hcode[i]);
    buildHeap(n);
    while(index > 1)
    {
        int sum = 0;
        sum += PopHeap(index);
        sum += PopHeap(index);
        ans += sum;
        InsertHeap(sum, index);
    }
    printf("%d\n", ans);
    return 0;
}
void buildHeap(int n)
{
    for(int i = n / 2; i >= 1; --i)//先從後開始建立最小堆
        adjustHeap(i, n);
}
void adjustHeap(int index, int n)
{
    while((index << 1) <= n)//確保在隊中調整堆
    {
        int tmp = index << 1;
        if(tmp + 1 <= n)
            if(Hcode[tmp] > Hcode[tmp + 1])
                tmp++;
        if(Hcode[tmp] < Hcode[index])//選擇最小的子節點,與父節點比較,判斷是否交換兩個元素
        {
            int t = Hcode[tmp];
            Hcode[tmp] = Hcode[index];
            Hcode[index] = t;
            index = tmp;
        }
        else
            break;
    }
}
int PopHeap(int &n)
{
    int x;
    if(n >= 1)
    {
        x = Hcode[1];
        Hcode[1] = Hcode[n--];//將最小值從堆中捨棄
        adjustHeap(1, n);//從頂開始調整堆
    }
    return x;
}
void InsertHeap(int x, int &n)
{
    int index = n + 1;
    n++;
    Hcode[n] = x;//在堆末添加元素
    while((index >> 1) > 0 && Hcode[index] < Hcode[index >> 1])//從低開始調整堆
    {
        int t = Hcode[index];//調整時,將最小元素提前
        Hcode[index] = Hcode[index >> 1];
        Hcode[index >> 1] = t;
        index >>= 1;
    }
}

Huffman Codes   (30分)

In 1953, David A. Huffman published his paper "A Method for the Construction of Minimum-Redundancy Codes", and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encountering a big problem: the Huffman codes are NOT unique. For example, given a string "aaaxuaxz", we can observe that the frequencies of the characters 'a', 'x', 'u' and 'z' are 4, 2, 1 and 1, respectively. We may either encode the symbols as {'a'=0, 'x'=10, 'u'=110, 'z'=111}, or in another way as {'a'=1, 'x'=01, 'u'=001, 'z'=000}, both compress the string into 14 bits. Another set of code can be given as {'a'=0, 'x'=11, 'u'=100, 'z'=101}, but {'a'=0, 'x'=01, 'u'=011, 'z'=001} is NOT correct since "aaaxuaxz" and "aazuaxax" can both be decoded from the code 00001011001001. The students are submitting all kinds of codes, and I need a computer program to help me determine which ones are correct and which ones are not.

Input Specification:

Each input file contains one test case. For each case, the first line gives an integerNNN (2≤N≤632\le N\le 632N63), then followed by a line that contains all the NNN distinct characters and their frequencies in the following format:

c[1] f[1] c[2] f[2] ... c[N] f[N]

where c[i] is a character chosen from {'0' - '9', 'a' - 'z', 'A' - 'Z', '_'}, andf[i] is the frequency ofc[i] and is an integer no more than 1000. The next line gives a positive integerMMM (≤1000\le 10001000), then followed by MMM student submissions. Each student submission consists of NNN lines, each in the format:

c[i] code[i]

where c[i] is the i-th character and code[i] is an non-empty string of no more than 63 '0's and '1's.

Output Specification:

For each test case, print in each line either "Yes" if the student's submission is correct, or "No" if not.

Note: The optimal solution is not necessarily generated by Huffman algorithm. Any prefix code with code length being optimal is considered correct.

Sample Input:

7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11

Sample Output:

Yes
Yes
No
No

解題思路:

題中所要求的編碼方式的檢驗,涉及兩方面:

1)WPL值得比較

2)是否是前綴編碼

對於2)容易忽略,但可用函數實現。

至於1)此處,是建立Huffman樹之後,利用先序遍歷對長度進行計算,然後將所得到長度與輸入所給的頻率運算得到。

此處的建樹,還是利用了最小堆(對於堆的知識此處略有欠缺)。

提交代碼:

編譯器:g++

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int MAXN = 64;
typedef struct Tnode tnode;
struct Tnode{
	int fre;
	char data;
	tnode *lc, *rc;
}; //Huffman樹的結點
struct Heap{
	int fre;
	int data;
	tnode *add;
}h[(MAXN << 1) - 1]; //最小堆的結點,其中的數據分別用於記錄字符頻率,字符,建樹需要的參數
int len[(MAXN << 2)]; //長度
int fre[(MAXN << 2)]; //頻率
char code[MAXN][MAXN]; //輸入的編碼方式
void buildHeap(int n); 
void adjust(int index, int n);
struct Heap popHeap(int n);
void pushHeap(tnode *t, int n);
void Swap(struct Heap &a, struct Heap &b); //以上函數用於建立最小堆
void buildHuffmanTree(int n);
tnode *getAdd(struct Heap node); //添加元素到Huffman樹上
int getWPL(void); //求WPL值
void DLR(tnode *t, int l); //求len值
bool islaw(int n); //是否是前綴編碼
int main()
{
	int n, m;
	char ch;
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i)
	{
		getchar();
		scanf("%c %d", &h[i].data, &h[i].fre);
		h[i].add = NULL; //表示爲添加到樹上
		fre[h[i].data] = h[i].fre;
	}
	buildHeap(n);
	buildHuffmanTree(n);
	int wpl0 = getWPL();
	
	scanf("%d", &m);//一下是判斷所給數據,是否是Huffman編碼
	for(int i = 0; i < m; ++i)
	{
		for(int j = 0; j < n; ++j)
		{
			getchar();
			scanf("%c %s", &ch, code[j]);
			len[ch] = strlen(code[j]);
		}
		bool Islaw = islaw(n);
		if(Islaw) //如果是前綴編碼
		{
			int wpl1 = getWPL();
			if(wpl1 == wpl0) printf("Yes\n"); //並且WPL值相同,則是Huffman編碼
			else printf("No\n");
		}
		else printf("No\n");
	}
	return 0;
}
void buildHeap(int n)
{
	for(int i = n >> 1; i >= 1; --i)
		adjust(i, n);
}
void adjust(int index, int n) //維護最小堆
{
	while((index << 1) <= n)
	{
		int tmp = index << 1;
		if(tmp + 1 <= n && h[tmp].fre > h[tmp + 1].fre)
			tmp = tmp + 1;
		if(h[tmp].fre < h[index].fre)
		{
			Swap(h[index], h[tmp]);
			index = tmp;
		}
		else break;
	}
}
struct Heap popHeap(int n) //彈出最小值
{
	struct Heap tmp = h[1];
	Swap(h[1], h[n]);
	adjust(1, n - 1);
	return tmp;
}
void Swap(struct Heap &a, struct Heap &b)
{
	struct Heap tmp = a;
	a = b;
	b = tmp;
}
void pushHeap(tnode *t, int n) //將元素壓入最小堆
{
	h[n].data = t->data, h[n].fre = t->fre;
	h[n].add = t; //表示已在樹上,表示已有孩子結點
	int index = n;
	struct Heap tmp = h[n];
	while((index >> 1) > 1)//維護最小堆
	{
		if(tmp.fre < h[index >> 1].fre)
		{
			h[index] = h[index >> 1];
			index >>= 1;
		}
		else break;
	}
	h[index] = tmp;
}
void buildHuffmanTree(int n)
{
	tnode *T = NULL;
	while(n > 1)
	{
		struct Heap node1 = popHeap(n);
		n--;
		struct Heap node2 = popHeap(n);
		tnode *t1 = getAdd(node1); //從最小堆中得到的最小值
		tnode *t2 = getAdd(node2);
		tnode *t = new tnode;
		t->fre = t1->fre + t2->fre; //將頻率累加
		t->data = ' '; //用空字符代替
		t->lc = t1, t->rc = t2;
		pushHeap(t, n); //將該父節點壓入最小堆
		if(n == 1) T = t; //如果只有一個元素,則作爲根結點
	}
	DLR(T, 0);
}
tnode *getAdd(struct Heap node)
{
	if(node.add == NULL) //如果爲加入到樹中,則作爲葉結點
	{
		tnode *tmp = new tnode;
		tmp->fre = node.fre;
		tmp->data = node.data;
		tmp->lc = tmp->rc = NULL;
		return tmp;
	}
	else return node.add; 否則將父結點作爲新的子結點,返回
}
int getWPL(void)
{
	int wpl = 0;
	for(int i = 0; i < MAXN << 1; ++i) //計算WPL
		wpl += len[i] * fre[i];
	for(int i = 0; i < MAXN << 1; ++i) //將len數組清空
		len[i] = 0;
	return wpl;
}
void DLR(tnode *t, int l)
{
	if(t)
	{
		if(t->data != ' ')
			len[t->data] = l;
		DLR(t->lc, l + 1);
		DLR(t->rc, l + 1);
	}
}
bool islaw(int n)
{
	for(int i = 0; i < n; ++i)
	{
		for(int j = i + 1; j < n; ++j)
		{
			int l1 = strlen(code[i]);
			int l2 = strlen(code[j]);
			int l;
			for(l = 0; l < l1 && l < l2; ++l)
				if(code[i][l] != code[j][l]) break;
			if(l >= l1 || l >= l2) return false;
		}
	}
	return true;
}

Windows消息隊列   (25分)

消息隊列是Windows系統的基礎。對於每個進程,系統維護一個消息隊列。如果在進程中有特定事件發生,如點擊鼠標、文字改變等,系統將把這個消息加到隊列當中。同時,如果隊列不是空的,這一進程循環地從隊列中按照優先級獲取消息。請注意優先級值低意味着優先級高。請編輯程序模擬消息隊列,將消息加到隊列中以及從隊列中獲取消息。

輸入格式:

輸入首先給出正整數N(≤105\le 10^5105),隨後N行,每行給出一個指令——GETPUT,分別表示從隊列中取出消息或將消息添加到隊列中。如果指令是PUT,後面就有一個消息名稱、以及一個正整數表示消息的優先級,此數越小表示優先級越高。消息名稱是長度不超過10個字符且不含空格的字符串;題目保證隊列中消息的優先級無重複,且輸入至少有一個GET

輸出格式:

對於每個GET指令,在一行中輸出消息隊列中優先級最高的消息的名稱和參數。如果消息隊列中沒有消息,輸出EMPTY QUEUE!。對於PUT指令則沒有輸出。

輸入樣例:

9
PUT msg1 5
PUT msg2 4
GET
PUT msg3 2
PUT msg4 4
GET
GET
GET
GET

輸出樣例:

msg2
msg3
msg4
msg1
EMPTY QUEUE!

解題思路:

根據最小堆的定義,建立堆。

同時當堆棧,發生不穩定時,進行必要的維護。

如有不明白,建議先了解堆的定義和堆的操作。

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 100002;
struct infi{
    char str[12];
    int Priority;
}Heap[MAXN];
void buildHeap(int index);
void Swap(struct infi &a, struct infi &b);
void adjust(int index);
int main()
{
    int n, index = 0;
    char com[5];
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
    {
        scanf("%s", com);
        if(com[0] == 'P')
        {
            index++;
            scanf("%s %d", Heap[index].str, &Heap[index].Priority);
            buildHeap(index);
        }
        else if(com[0] == 'G')
        {
            if(index >= 1)
            {
                struct infi tmp = Heap[1];
                Swap(Heap[1], Heap[index]);
                index--;
                adjust(index);
                printf("%s\n", tmp.str);
            }
            else
                printf("EMPTY QUEUE!\n");
        }
    }
    return 0;
}
void buildHeap(int index)
{
    while((index >> 1) > 0 && Heap[index].Priority < Heap[index >> 1].Priority)
    {
        Swap(Heap[index], Heap[index >> 1]);
        index >>= 1;
    }
}
void Swap(struct infi &a, struct infi &b)
{
    struct infi tmp = a;
    a = b;
    b = tmp;
}
void adjust(int n)
{
    int index = 1;
    while((index << 1) < n)
    {
        int tmp = index << 1;
        if(tmp + 1 < n)
            if(Heap[tmp].Priority > Heap[tmp + 1].Priority)
                tmp++;
        if(Heap[tmp].Priority < Heap[index].Priority)
        {
            Swap(Heap[tmp], Heap[index]);
            index = tmp;
        }
        else
        {
            break;
        }
    }
}

堆中的路徑   (25分)

將一系列給定數字插入一個初始爲空的小頂堆H[]。隨後對任意給定的下標i,打印從H[i]到根結點的路徑。

輸入格式:

每組測試第1行包含2個正整數NNNMMM(≤1000\le 10001000),分別是插入元素的個數、以及需要打印的路徑條數。下一行給出區間[-10000, 10000]內的NNN個要被插入一個初始爲空的小頂堆的整數。最後一行給出MMM個下標。

輸出格式:

對輸入中給出的每個下標i,在一行中輸出從H[i]到根結點的路徑上的數據。數字間以1個空格分隔,行末不得有多餘空格。

輸入樣例:

5 3
46 23 26 24 10
5 4 3

輸出樣例:

24 23 10
46 23 10
26 10

解題思路:

直接建堆,然後根據堆的性質,輸出結果

提交代碼:

編譯器:g++

#include <iostream>
using namespace std;
const int MAXN = 1002;
int H[MAXN];
void Create(int n);
void Output(int index);
int main()
{
    int n, k, index;
    cin>>n>>k;
    Create(n);
    for(int i = 0; i < k; ++i)
    {
        cin>>index;
        Output(index);
    }
    return 0;
}
void Create(int n)
{
    int cnt = 1,index = 0;
    for(int i = 0; i < n; ++i)
    {
        index = cnt;
        cin>>H[cnt++];
        while((index>>1) > 0 && H[index] < H[index>>1])
        {
            int tmp = H[index];
            H[index] = H[index>>1];
            H[index>>1] = tmp;
            index >>= 1;
        }
    }
}
void Output(int index)
{
    int cnt = 0;
    while(index > 0)
    {
        if(cnt) cout<<' ';
        cout<<H[index];
        index >>= 1;
        cnt++;
    }
    cout<<endl;
}

並查集

朋友圈   (25分)

某學校有N個學生,形成M個俱樂部。每個俱樂部裏的學生有着一定相似的興趣愛好,形成一個朋友圈。一個學生可以同時屬於若干個不同的俱樂部。根據“我的朋友的朋友也是我的朋友”這個推論可以得出,如果A和B是朋友,且B和C是朋友,則A和C也是朋友。請編寫程序計算最大朋友圈中有多少人。

輸入格式:

輸入的第一行包含兩個正整數N(≤\le30000)和M(≤\le1000),分別代表學校的學生總數和俱樂部的個數。後面的M行每行按以下格式給出1個俱樂部的信息,其中學生從1~N編號:

第i個俱樂部的人數Mi(空格)學生1(空格)學生2 … 學生Mi

輸出格式:

輸出給出一個整數,表示在最大朋友圈中有多少人。

輸入樣例:

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

輸出樣例:

4

解題思路:

在一個圈子裏假定一個組長,該組長有一個該組內任意人都可複製的符號

當輸入的人員是某一組的成員時,由該組成員複製符號給該人員

最後利用這個特殊符號統計各組人員多少

(此處的還未對並查集知識點進行整理)

提交代碼:

編譯器:g++

#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 30001;
int root[MAXN];
int Find(int x) //查找函數,用於將符號複製
{
    if(x != root[x])
        root[x] = Find(root[x]);
    return root[x];
}
int main()
{
    int n, m, k;
    int a, b;
    scanf("%d%d", &n, &m);
    for(int i = 0; i <= n; ++i)
        root[i] = i;
    for(int i = 0; i < m; ++i)
    {
        scanf("%d %d", &k, &a);
        int x = Find(a);
        for(int j = 1; j < k; ++j)
        {
            scanf("%d", &b);
            int y = Find(b);
            if(x != y) //如果同一個圈子內的人有不同的符號,則統一爲一個符號
                root[y] = x;
        }
    }
    for(int i = 1; i <= n; ++i)
        Find(i);
    sort(root + 1, root + n + 1);
    int Max = 0, cnt = 0, tmp = root[1];
    for(int i = 1; i <= n; ++i) //統計各組內人數,並記錄最大值
    {
        if(root[i] == tmp)
            cnt++;
        else
        {
            if(Max < cnt)
                Max = cnt;
            tmp = root[i], cnt = 1;
        }
    }
    printf("%d\n", Max);
    return 0;
}

File Transfer   (25分)

We have a network of computers and a list of bi-directional connections. Each of these connections allows a file transfer from one computer to another. Is it possible to send a file from any computer on the network to any other?

Input Specification:

Each input file contains one test case. For each test case, the first line containsNNN (2≤N≤1042\le N\le 10^42N104), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 andNNN. Then in the following lines, the input is given in the format:

I c1 c2

where I stands for inputting a connection between c1 andc2; or

C c1 c2

where C stands for checking if it is possible to transfer files betweenc1 andc2; or

S

where S stands for stopping this case.

Output Specification:

For each C case, print in one line the word "yes" or "no" if it is possible or impossible to transfer files betweenc1 andc2, respectively. At the end of each case, print in one line "The network is connected." if there is a path between any pair of computers; or "There arek components." wherek is the number of connected components in this network.

Sample Input 1:

5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S

Sample Output 1:

no
no
yes
There are 2 components.

Sample Input 2:

5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S

Sample Output 2:

no
no
yes
yes
The network is connected.

解題思路:

依舊假定一個組長,之後對輸入的數據進行模擬並判斷是否是同一組的人員。

如果是同一組的,則總人數在總人數中減少一,表示剩下n - 1個不同的組。

直到n == 1的時候,只有一個組,表示網絡聯通。

(此處的還未對並查集知識點進行整理)

提交代碼:

編譯器:g++

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAXN = 10002;
int root[MAXN];
int Find(int x);
int main()
{
	int n;
	char ch;
	int a, b;
	scanf("%d", &n);
	getchar();
	for(int i = 1; i <= n; ++i)
		root[i] = i;
	while((ch = getchar()) != 'S')
	{
		scanf("%d%d", &a, &b);
		getchar();
		int x = Find(a);
		int y = Find(b);
		if(ch == 'C')
		{
			if(x != y)
				printf("no\n");
			else
				printf("yes\n");
		}
		else if(ch == 'I')
		{
			if(x != y)
				root[x] = y, n--;
		}
	}
	if(n == 1)
		printf("The network is connected.\n");
	else
		printf("There are %d components.", n);
	return 0;
}
int Find(int x)
{
	if(x != root[x])
		root[x] = Find(root[x]);
	return root[x];
}


發佈了48 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章