第一章 绪论 1 最大子列和问题 给定K个整数组成的序列{ N1, N2, …, NK },“连续子列”被定义为{ Ni, Ni+1, …, Nj },其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
输入格式: 输入第1行给出正整数K (≤100000);第2行给出K个整数,其间以空格分隔。 输入样例:
输出格式: 在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。 输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> int main () { int result=0 ,thissum=0 ,N,digit; scanf ("%d" ,&N); for (int i=0 ;i<N;i++){ scanf ("%d" ,&digit); thissum+=digit; if (thissum>result) result=thissum; if (thissum<0 ) thissum=0 ; } printf ("%d" ,result); return 0 ; }
2 最大子列和问题 给定K个整数组成的序列{ N1, N2, …, NK },“连续子列”被定义为{ Ni, Ni+1, …, Nj },其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和,并输出整个序列的第一个和最后一个数。
输入格式: 输入第1行给出正整数K (≤100000);第2行给出K个整数,其间以空格分隔。 输入样例:
1 2 10 -10 1 2 3 4 -5 -23 3 7 -21
输出格式: 对于每个测试用例,在一行中输出最大和,以及最大子序列的第一个和最后一个数字。数字必须用一个空格隔开,但行尾不能有多余的空格。如果最大子序列不唯一,则输出索引i和j最小的子序列(如示例所示)。如果所有K个数都是负数,那么它的最大和被定义为0,你应该输出整个序列的第一个和最后一个数。 输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> int main () { int result = 0 , thissum = 0 , N, digit, startnew = 0 , start = 0 , end , trigger = 0 ; if (scanf ("%d" , &N)) {}; end = N -1 ; for (int i = 0 ; i < N; i++) { if (scanf ("%d" , &digit)) {}; thissum += digit; if (thissum > result) { if (trigger == 1 ) { trigger = 0 ; start = digit; } end = digit; result = thissum; } if (thissum < 0 ) { trigger = 1 ; thissum = 0 ; } } printf ("%d %d %d\n" , result, start, end ); return 0 ; }
第二章 线性结构 1 一元多项式的乘法与加法运算 设计函数分别求两个一元多项式的乘积与和。
输入格式: 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。 输入样例:
1 2 4 3 4 -5 2 6 1 -2 0 3 5 20 -7 4 3 1
输出格式: 输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。 输出样例:
1 2 15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1 5 20 -4 4 -5 2 9 1 -2 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct PolyNode *Polynomial ;struct PolyNode { int coef; int expon; Polynomial link; }; void Attach (int c, int e, Polynomial* pRear) { Polynomial P; P = (Polynomial)malloc (sizeof (struct PolyNode)); P->coef = c; P->expon = e; P->link = NULL ; (*pRear)->link = P; *pRear = P; } Polynomial ReadPoly () { Polynomial P, Rear, t; int c, e, N; scanf ("%d" , &N); P = (Polynomial)malloc (sizeof (struct PolyNode)); P->link = NULL ; Rear = P; while (N--) { scanf ("%d %d" , &c, &e); if (c != 0 ) Attach(c, e, &Rear); } t = P; P = P->link; free (t); return P; } int Compare (int e1, int e2) { if (e1 > e2) return 1 ; else if (e1 < e2) return -1 ; else return 0 ; } Polynomial Add (Polynomial P1, Polynomial P2) { Polynomial front, rear, temp; int sum; rear = (Polynomial)malloc (sizeof (struct PolyNode)); front = rear; while (P1 && P2) { switch (Compare(P1->expon, P2->expon)) { case 1 : Attach(P1->coef, P1->expon, &rear); P1 = P1->link; break ; case -1 : Attach(P2->coef, P2->expon, &rear); P2 = P2->link; break ; case 0 : sum = P1->coef + P2->coef; if (sum) Attach(sum, P1->expon, &rear); P1 = P1->link; P2 = P2->link; break ; } } for (; P1; P1 = P1->link) Attach(P1->coef, P1->expon, &rear); for (; P2; P2 = P2->link) Attach(P2->coef, P2->expon, &rear); rear->link = NULL ; temp = front; front = front->link; free (temp); return front; } Polynomial Mult (Polynomial P1, Polynomial P2) { Polynomial P, Rear, t1, t2, t; int c, e; if (!P1 || !P2) return NULL ; t1 = P1; t2 = P2; P = (Polynomial)malloc (sizeof (struct PolyNode)); P->link = NULL ; Rear = P; while (t2) { Attach(t1->coef * t2->coef, t1->expon + t2->expon, &Rear); t2 = t2->link; } t1 = t1->link; while (t1) { t2 = P2; Rear = P; while (t2) { e = t1->expon + t2->expon; c = t1->coef * t2->coef; while (Rear->link && Rear->link->expon > e) Rear = Rear->link; if (Rear->link && Rear->link->expon == e) { if (Rear->link->coef + c) Rear->link->coef += c; else { t = Rear->link; Rear->link = t->link; free (t); } } else { t = (Polynomial)malloc (sizeof (struct PolyNode)); t->coef = c; t->expon = e; t->link = Rear->link; Rear->link = t; Rear = Rear->link; } t2 = t2->link; } t1 = t1->link; } t2 = P; P = P->link; free (t2); return P; } void PrintPoly (Polynomial P) { int c, e, flag = 0 ; if (!P) { printf ("0 0" ); return ; } while (P) { c = P->coef; e = P->expon; if (!flag) flag = 1 ; else printf (" " ); printf ("%d %d" , c, e); P = P->link; } } int main () { Polynomial P1, P2, PP, PS; P1 = ReadPoly(); P2 = ReadPoly(); PP = Mult(P1, P2); PrintPoly(PP); printf ("\n" ); PS = Add(P1, P2); PrintPoly(PS); return 0 ; }
2 两个有序链表序列的合并 本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。 L1和L2是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Merge要将L1和L2合并为一个非递减的整数序列。应直接使用原序列中的结点,返回归并后的带头结点的链表头指针。
输入样例:
输出样例:
1 2 3 1 2 3 4 5 6 8 10 NULL NULL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 #include <stdio.h> #include <stdlib.h> typedef int ElementType;typedef struct Node * PtrToNode ;struct Node { ElementType Data; PtrToNode Next; }; typedef PtrToNode List;List Read () ; void Print (List L) ; List Merge (List L1, List L2) ;int main () { List L1, L2, L; L1 = Read(); L2 = Read(); L = Merge(L1, L2); Print(L); Print(L1); Print(L2); return 0 ; } void Attach (int d, List* pRear) { List P; P = (List)malloc (sizeof (struct Node)); P->Data = d; P->Next = NULL ; (*pRear)->Next = P; *pRear = P; } List Merge (List L1, List L2) { List temp1 = L1->Next; List temp2 = L2->Next; List p; p = (List)malloc (sizeof (struct Node)); p->Next = NULL ; List temp = p; while (temp1 && temp2) { if (temp1->Data < temp2->Data) { temp->Next = temp1; temp1 = temp1->Next; temp = temp->Next; } else { temp->Next = temp2; temp2 = temp2->Next; temp = temp->Next; } } while (temp1 != NULL ) { temp->Next = temp1; temp1 = temp1->Next; temp = temp->Next; } while (temp2 != NULL ) { temp->Next = temp2; temp2 = temp2->Next; temp = temp->Next; } L1->Next = NULL ; L2->Next = NULL ; temp->Next = NULL ; return p; } List Read () { List P, Rear, t; int d, N; scanf ("%d" , &N); P = (List)malloc (sizeof (struct Node)); P->Next = NULL ; Rear = P; while (N--) { scanf ("%d" , &d); Attach(d, &Rear); } return P; } void Print (List L) { if (L->Next == NULL ) { printf ("NULL\n" ); return ; } List temp = L->Next; while (temp) { printf ("%d " , temp->Data); temp = temp->Next; } printf ("\n" ); }
3 Pop Sequence 给定一个最多能保存M个数的堆栈。按1,2,3,…,N的顺序推N个数字,然后随机弹出。您应该知道给定的数字序列是否可能是堆栈的弹出序列。例如,如果M是5,N是7,我们可以从堆栈中获得1,2,3,4,5,6,7,但不能从3,2,1,7,5,6,4。
输入格式: 每个输入文件包含一个测试用例。对于每种情况,第一行包含3个数字(都不超过1000):M(堆栈的最大容量)、N(推送序列的长度)和K(要检查的pop序列的数量)。接下来是K行,每行包含N个数字的pop序列。一行中的所有数字都用空格隔开。 输入样例:
1 2 3 4 5 6 5 7 5 1 2 3 4 5 6 7 3 2 1 7 5 6 4 7 6 5 4 3 2 1 5 6 4 3 7 2 1 1 7 6 5 4 3 2
输出格式: 对于每个弹出序列,如果确实是堆栈的可能弹出序列,则在一行中打印“YES”,如果不是,则打印“NO”。 输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <stdio.h> #include <stdlib.h> int main () { int i, j, m, n, k, a[1000 ][1000 ], b[1000 ], stack [1000 ], stack_index, top; scanf ("%d %d %d" , &m, &n, &k); for (i = 0 ; i < k; i++) { for (j = 0 ; j < n; j++) { scanf ("%d" , &a[i][j]); } stack_index = 1 ; top = 1 ; stack [1 ] = 1 ; for (j = 0 ; j < n; j++) { while (a[i][j] > top) { stack_index++; top++; stack [stack_index] = top; } if (stack_index > m || a[i][j] < stack [stack_index]) { b[i] = 0 ; break ; } if (a[i][j] == stack [stack_index]) { stack_index--; } } if (stack_index == 0 ) b[i] = 1 ; } for (i = 0 ; i < k; i++) { if (b[i] == 0 ) printf ("NO" ); else if (b[i] == 1 ) printf ("YES" ); printf ("\n" ); } return 0 ; }
第三章 树结构(上) 1 树的同构 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。
1
图1 图2 输入格式: 输入给出2棵二叉树树的信息。对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N−1编号);随后N行,第i行对应编号第i个结点,给出该结点中存储的1个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出“-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。
输出格式: 如果两棵树是同构的,输出“Yes”,否则输出“No”。
输入样例1(对应图1):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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(对应图1):
输入样例2(对应图2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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(对应图2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 import java.util.Arrays;import java.util.Scanner;class TreeNode { String val; int left; int right; } public class Main { private static TreeNode[] T1 = new TreeNode[10 ]; private static TreeNode[] T2 = new TreeNode[10 ]; private static int [] check = new int [10 ]; public static void main (String[] args) { Scanner scan = new Scanner(System.in); int T = scan.nextInt(); Arrays.fill(check, 0 ); for (int i = 0 ; i < T; i++) { T1[i] = new TreeNode(); T1[i].val = scan.next(); String left = scan.next(); String right = scan.next(); if (left.equals("-" )) { T1[i].left = -1 ; } else { T1[i].left = Integer.parseInt(left); check[Integer.parseInt(left)] = 1 ; } if (right.equals("-" )) { T1[i].right = -1 ; } else { T1[i].right = Integer.parseInt(right); check[Integer.parseInt(right)] = 1 ; } } int root = -1 ; for (int i = 0 ; i < T; i++) { if (check[i] == 0 ) { root = i; } } T = scan.nextInt(); Arrays.fill(check, 0 ); for (int i = 0 ; i < T; i++) { T2[i] = new TreeNode(); T2[i].val = scan.next(); String left = scan.next(); String right = scan.next(); if (left.equals("-" )) { T2[i].left = -1 ; } else { T2[i].left = Integer.parseInt(left); check[Integer.parseInt(left)] = 1 ; } if (right.equals("-" )) { T2[i].right = -1 ; } else { T2[i].right = Integer.parseInt(right); check[Integer.parseInt(right)] = 1 ; } } int root1 = -1 ; for (int i = 0 ; i < T; i++) { if (check[i] == 0 ) { root1 = i; } } System.out.println(Isomorphic(root, root1) ? "Yes" : "No" ); } public static boolean Isomorphic (int node1, int node2) { if (node1 == -1 && node2 == -1 ) { return true ; } if ((node1 == -1 && node2 != -1 ) || (node1 != -1 && node2 == -1 ) || (!T1[node1].val.equals(T2[node2].val))) { return false ; } if (T1[node1].left == -1 && T2[node2].left == -1 ) { return Isomorphic(T1[node1].right, T2[node2].right); } if ((T1[node1].left != -1 && T2[node2].left != -1 ) && T1[T1[node1].left].val.equals(T2[T2[node2].left].val)) { return (Isomorphic(T1[node1].left, T2[node2].left) && Isomorphic(T1[node1].right, T2[node2].right)); } else { return (Isomorphic(T1[node1].left, T2[node2].right) && Isomorphic(T1[node1].right, T2[node2].left)); } } }
2 List Leaves 给定一棵树,您应该按照从上到下,从左到右的顺序列出所有叶子。
输入格式: 每个输入文件包含一个测试用例。对于每种情况,第一行给出一个正整数N(≤ 1 0),这是树中的节点的总数-并且因此节点编号从0到N − 1。然后N行跟随,每行对应一个节点,并给出该节点的左,右子级的索引。如果孩子不存在,将在该位置放置一个“-”。任何一对孩子都用空格隔开。
输出格式: 对于每个测试用例,按从上到下,从左到右的顺序在一行中打印所有叶子的索引。相邻数字之间必须恰好有一个空格,并且在行尾不能有多余的空格。
输入样例:
1 2 3 4 5 6 7 8 9 8 1 -- - 0 -2 7 - - - - 5 -4 6
输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 import java.util.Arrays;import java.util.Scanner;import java.util.LinkedList;import java.util.Queue;class TreeNode { int left; int right; } public class Main { private static TreeNode[] tree = new TreeNode[10 ]; private static int [] check = new int [10 ]; private static Queue<Integer> queue = new LinkedList<Integer>(); private static boolean flag = false ; public static void main (String[] args) { Scanner scan = new Scanner(System.in); int T = scan.nextInt(); Arrays.fill(check, 0 ); for (int i = 0 ; i < T; i++) { tree[i] = new TreeNode(); String left = scan.next(); String right = scan.next(); if (left.equals("-" )) { tree[i].left = -1 ; } else { tree[i].left = Integer.parseInt(left); check[Integer.parseInt(left)] = 1 ; } if (right.equals("-" )) { tree[i].right = -1 ; } else { tree[i].right = Integer.parseInt(right); check[Integer.parseInt(right)] = 1 ; } } int root = -1 ; for (int i = 0 ; i < T; i++) { if (check[i] == 0 ) { root = i; } } printLeaves(root); } public static void printLeaves (int node) { if (tree[node].left != -1 ) { queue.offer(tree[node].left); } if (tree[node].right != -1 ) { queue.offer(tree[node].right); } if (tree[node].left == -1 && tree[node].right == -1 ) { if (flag) { System.out.print(" " + node); } else { flag = true ; System.out.print(node); } } Object n = queue.poll(); if (n == null ) { return ; } else { printLeaves((int )n); } } }
第四章 树(中) 1 是否同一棵二叉搜索树 给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{2, 1, 3}和{2, 3, 1}插入初始为空的二叉搜索树,都得到一样的结果。于是对于输入的各种插入序列,你需要判断它们是否能生成一样的二叉搜索树。
输入格式:
输入包含若干组测试数据。每组数据的第1行给出两个正整数N (≤10)和L,分别是每个序列插入元素的个数和需要检查的序列个数。第2行给出N个以空格分隔的正整数,作为初始插入序列。最后L行,每行给出N个插入的元素,属于L个需要检查的序列。 简单起见,我们保证每个插入序列都是1到N的一个排列。当读到N为0时,标志输入结束,这组数据不要处理。
输入样例:
1 2 3 4 5 6 7 8 4 2 3 1 4 2 3 4 1 2 3 2 4 1 2 1 2 1 1 2 0
输出格式:
对每一组需要检查的序列,如果其生成的二叉搜索树跟对应的初始序列生成的一样,输出“Yes”,否则输出“No”。
输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 import java.util.Scanner;class TreeNode { int val; TreeNode left; TreeNode right; boolean flag; } public class Main { public static void main (String[] args) { Scanner scan = new Scanner(System.in); int N = scan.nextInt(); while (N != 0 ) { int L = scan.nextInt(); TreeNode root = new TreeNode(); root.val = scan.nextInt(); for (int i = 1 ; i < N; i++) { int val = scan.nextInt(); root = Insert(root, val); } for (int i = 0 ; i < L; i++) { boolean flag = true ; int val = scan.nextInt(); if (val != root.val) { flag = false ; } else { root.flag = true ; } for (int j = 1 ; j < N; j++) { int nextVal = scan.nextInt(); if (flag) { flag = Check(root, nextVal); } } if (flag) { System.out.println("Yes" ); } else { System.out.println("No" ); } Reset(root); } N = scan.nextInt(); } } private static TreeNode Insert (TreeNode node, int val) { if (node == null ) { node = new TreeNode(); node.val = val; } else { if (val < node.val) { node.left = Insert(node.left, val); } else if (val > node.val) { node.right = Insert(node.right, val); } } return node; } private static boolean Check (TreeNode node, int val) { if (node.flag) { if (val < node.val) { return Check(node.left, val); } else if (val > node.val) { return Check(node.right, val); } else { return false ; } } else { if (val == node.val) { node.flag = true ; return true ; } else { return false ; } } } private static void Reset (TreeNode node) { if (node.left != null ) { Reset(node.left); } if (node.right != null ) { Reset(node.right); } node.flag = false ; } }
第五章 树(下) 1 堆中的路径 将一系列给定数字插入一个初始为空的最小堆H[]。随后对任意给定的下标i,打印从H[i]到根结点的路径。
输入格式:
每组测试第1行包含2个正整数N和M(≤1000),分别是插入元素的个数、以及需要打印的路径条数。下一行给出区间[-10000, 10000]内的N个要被插入一个初始为空的小顶堆的整数。最后一行给出M个下标。
输入样例:
1 2 3 5 3 46 23 26 24 10 5 4 3
输出格式:
对输入中给出的每个下标i,在一行中输出从H[i]到根结点的路径上的数据。数字间以1个空格分隔,行末不得有多余空格。
输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import java.util.Scanner;class Heap { int [] heap; int size; int capacity; } public class Main { public static void main (String[] args) { Scanner scan = new Scanner(System.in); int N = scan.nextInt(); int M = scan.nextInt(); Heap minHeap = new Heap(); minHeap.heap = new int [N + 1 ]; minHeap.size = 0 ; minHeap.capacity = N; minHeap.heap[0 ] = -20000 ; for (int i = 0 ; i < N; i++) { minHeap = Insert(minHeap, scan.nextInt()); } for (int i = 0 ; i < M; i++) { for (int index = scan.nextInt(); index > 0 ; index /= 2 ) { if (index == 1 ) { System.out.print(minHeap.heap[index]); } else { System.out.print(minHeap.heap[index] + " " ); } } if (i != M - 1 ) System.out.print("\n" ); } } private static Heap Insert (Heap minHeap, int val) { if (minHeap.size < minHeap.capacity) { int i = ++minHeap.size; for ( ; minHeap.heap[i / 2 ] > val; i /= 2 ) { minHeap.heap[i] = minHeap.heap[i / 2 ]; } minHeap.heap[i] = val; } return minHeap; } }
第六章 图(上) 1 列出连通集 给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式: 输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。 输入样例:
1 2 3 4 5 6 7 8 6 0 7 0 1 2 0 4 1 2 4 3 5
输出格式: 按照”{ v1 v2 … vk }”的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。 输出样例:
1 2 3 4 5 6 { 0 1 4 2 7 } { 3 5 } { 6 } { 0 1 2 7 4 } { 3 5 } { 6 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 import java.util.Scanner;import java.util.LinkedList;import java.util.Queue;class LGraph { int Nv; int Ne; int [][] map = new int [10 ][10 ]; } public class Main { private static Queue<Integer> queue = new LinkedList<Integer>(); private static boolean [] Visited1 = new boolean [10 ]; private static boolean [] Visited2 = new boolean [10 ]; public static LGraph Graph = new LGraph(); public static void main (String[] args) { Scanner scan = new Scanner(System.in); Graph.Nv = scan.nextInt(); Graph.Ne = scan.nextInt(); for (int i = 0 ; i < Graph.Ne; i++) { int V1 = Integer.parseInt(scan.next()); int V2 = Integer.parseInt(scan.next()); if (V1 == V2) continue ; Graph.map[V1][V2] = 1 ; Graph.map[V2][V1] = 1 ; } for (int i = 0 ; i < Graph.Nv; i++) { if (!Visited1[i]) { System.out.print("{ " ); DFS(i); System.out.print("}\n" ); } } for (int i = 0 ; i < Graph.Nv; i++) { if (!Visited2[i]) { System.out.print("{ " ); BFS(i); System.out.print("}\n" ); } } } public static void DFS (int node) { Visited1[node] = true ; System.out.print(node + " " ); for (int i =0 ; i < Graph.Nv; i++) { if (Graph.map[node][i] == 1 && !Visited1[i]) DFS(i); } } public static void BFS (int node) { queue.offer(node); while (!queue.isEmpty()) { int n = queue.poll(); if (!Visited2[n]) { Visited2[n] = true ; System.out.print(n + " " ); } for (int i =0 ; i < Graph.Nv; i++) { if (Graph.map[n][i] == 1 && !Visited2[i]) queue.offer(i); } } } }
2 六度空间 “六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”
假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。
输入格式: 输入第1行给出两个正整数,分别表示社交网络图的结点数N(1<N≤103 ,表示人数)、边数M(≤33×N,表示社交关系数)。随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个结点的编号(节点从1到N编号)。 输入样例:
1 2 3 4 5 6 7 8 9 10 10 9 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
输出格式: 对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。 输出样例:
1 2 3 4 5 6 7 8 9 10 1 : 70.00 %2 : 80.00 %3 : 90.00 %4 : 100.00 %5 : 100.00 %6 : 100.00 %7 : 100.00 %8 : 90.00 %9 : 80.00 %10 : 70.00 %
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 import java.util.Scanner;import java.util.LinkedList;import java.util.Queue;class LGraph { int Nv; int Ne; Vertex[] vertexArray = new Vertex[1000 ]; } class Vertex { int verName; Vertex nextNode; } public class Main { private static Queue<Integer> queue = new LinkedList<Integer>(); private static boolean [] Visited = new boolean [1000 ]; public static LGraph Graph = new LGraph(); public static void main (String[] args) { Scanner scan = new Scanner(System.in); Graph.Nv = scan.nextInt(); Graph.Ne = scan.nextInt(); for (int i = 0 ; i < Graph.Ne; i++) { int v1 = Integer.parseInt(scan.next()) - 1 ; int v2 = Integer.parseInt(scan.next()) - 1 ; if (v1 == v2) continue ; Vertex VN1 = new Vertex(); VN1.verName = v2; Vertex VN2 = new Vertex(); VN2.verName = v1; Vertex VN = Graph.vertexArray[v1]; Graph.vertexArray[v1] = VN1; VN1.nextNode = VN; VN = Graph.vertexArray[v2]; Graph.vertexArray[v2] = VN2; VN2.nextNode = VN; } for (int i = 0 ; i < Graph.Nv; i++) { for (int j = 0 ; j < Graph.Nv; j++) Visited[j] = false ; int x = i + 1 ; System.out.print(x + ": " ); BFS(i); if (i != Graph.Nv - 1 ) { System.out.print("\n" ); } } } public static void BFS (int node) { int count = 0 , tail = 0 , last = node, level = 0 ; queue.offer(node); while (!queue.isEmpty()) { int n = queue.poll(); if (!Visited[n]) { count++; Visited[n] = true ; Vertex no = Graph.vertexArray[n]; while (no != null ) { if (!Visited[no.verName]) { queue.offer(no.verName); tail = no.verName; } no = no.nextNode; } if (n == last) { last = tail; level++; } if (level == 7 ) { queue.clear(); break ; } } } double rate = (double ) count * 100 / Graph.Nv; System.out.print(String.format("%.2f" , rate) + "%" ); } }
小技巧:利用tail和last记录BFS当前层数
3
第九章 排序(上) 1 排序 给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。
输入格式: 输入第一行给出正整数N(≤105 ),随后一行给出N个(长整型范围内的)整数,其间以空格分隔。 输入样例:
1 2 11 4 981 10 -17 0 -20 29 50 8 43 -5
输出格式: 在一行中输出从小到大排序后的结果,数字间以1个空格分隔,行末不得有多余空格。 输出样例:
1 -20 -17 -5 0 4 8 10 29 43 50 981
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 #include <stdio.h> #include <stdlib.h> void Merge ( int A[], int TmpA[], int L, int R, int RightEnd ) { int LeftEnd, NumElements, Tmp; int i; LeftEnd = R - 1 ; Tmp = L; NumElements = RightEnd - L + 1 ; while ( L <= LeftEnd && R <= RightEnd ) { if ( A[L] <= A[R] ) TmpA[Tmp++] = A[L++]; else TmpA[Tmp++] = A[R++]; } while ( L <= LeftEnd ) TmpA[Tmp++] = A[L++]; while ( R <= RightEnd ) TmpA[Tmp++] = A[R++]; for ( i = 0 ; i < NumElements; i++, RightEnd -- ) A[RightEnd] = TmpA[RightEnd]; } void Merge_pass ( int A[], int TmpA[], int N, int length ) { int i, j; for ( i=0 ; i <= N-2 *length; i += 2 *length ) Merge( A, TmpA, i, i+length, i+2 *length-1 ); if ( i+length < N ) Merge( A, TmpA, i, i+length, N-1 ); else for ( j = i; j < N; j++ ) TmpA[j] = A[j]; } void Merge_Sort ( int A[], int N ) { int length; int *TmpA; length = 1 ; TmpA =(int *) malloc ( N * sizeof ( int ) ); if ( TmpA != NULL ) { while ( length < N ) { Merge_pass( A, TmpA, N, length ); length *= 2 ; Merge_pass( TmpA, A, N, length ); length *= 2 ; } free ( TmpA ); } else printf ( "空间不足" ); } int main () { int N; int * a; scanf ("%d" ,&N); a = new int [N]; for (int i=0 ; i<N; ++i) scanf ("%d" ,&a[i]); Merge_Sort( a, N ); printf ("%d" ,a[0 ]); for (int i=1 ; i<N; ++i) printf (" %d" ,a[i]); delete [] a; return 0 ; }
第十章 排序(下) 1 统计工龄 给定公司N名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。
输入格式: 输入首先给出正整数N(≤105 ),即员工总人数;随后给出N个整数,即每个员工的工龄,范围在[0, 50]。 输入样例:
输出格式: 按工龄的递增顺序输出每个工龄的员工个数,格式为:“工龄:人数”。每项占一行。如果人数为0则不输出该项。 输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package test;import java.lang.reflect.Array;import java.util.Scanner;public class Main { public static void main (String[] args) { int [] A = new int [51 ]; Scanner scan = new Scanner(System.in); int N = scan.nextInt(); for (int i = 0 ; i < N; i++) { int n = scan.nextInt(); A[n] += 1 ; } for (int i = 0 ; i < 51 ; i++) { if (A[i] != 0 ) { System.out.println(i + ":" + A[i]); } } } }
第十一章 散列查找 1 电话聊天狂人 给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。
输入格式: 输入首先给出正整数N(≤105 ),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。 输入样例:
1 2 3 4 5 4 13005711862 13588625832 13505711862 13088625832 13588625832 18087925832 15005713862 13588625832
输出格式: 在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。 输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.*;public class Main { public static void main (String[] args) { Map<String, Integer> phoneNumber = new HashMap<String, Integer>(); Scanner scan = new Scanner(System.in); int N = scan.nextInt(); for (int i = 0 ; i < 2 * N; i++) { String n = scan.next(); if (phoneNumber.containsKey(n)) { phoneNumber.put(n, phoneNumber.get(n) + 1 ); } else { phoneNumber.put(n, 1 ); } } int max = 0 , value = 0 ; List<String> number=new ArrayList<>(); String Num = "99999999999" ; for (String key:phoneNumber.keySet()){ value = phoneNumber.get(key); if (max < value){ max = value; } } for (String key:phoneNumber.keySet()){ if (phoneNumber.get(key) == max){ number.add(key); } } if (number.size() == 1 ) { System.out.println(number.get(0 ) + " " + max); } else { for (String key : number) { if (key.compareTo(Num) < 0 ) { Num = key; } } System.out.println(Num + " " + max + " " + number.size()); } } }
2 QQ帐户的申请与登陆 实现QQ新帐户申请和老帐户登陆的简化版功能。最大挑战是:据说现在的QQ号码已经有10位数了。
输入格式: 输入首先给出正整数N(≤105 ),随后给出N行指令。每行指令的格式为:“命令符(空格)QQ号码(空格)密码”。其中命令符为“N”(代表New)时表示要新申请一个QQ号,后面是新帐户的号码和密码;命令符为“L”(代表Login)时表示是老帐户登陆,后面是登陆信息。QQ号码为一个不超过10位、但大于1000(据说QQ老总的号码是1001)的整数。密码为不小于6位、不超过16位、且不包含空格的字符串。 输入样例:
1 2 3 4 5 6 5 L 1234567890 myQQ@qq.com N 1234567890 myQQ@qq.com N 1234567890 myQQ@qq.com L 1234567890 myQQ@qq L 1234567890 myQQ@qq.com
输出格式: 针对每条指令,给出相应的信息: 1)若新申请帐户成功,则输出“New: OK”; 2)若新申请的号码已经存在,则输出“ERROR: Exist”; 3)若老帐户登陆成功,则输出“Login: OK”; 4)若老帐户QQ号码不存在,则输出“ERROR: Not Exist”; 5)若老帐户密码错误,则输出“ERROR: Wrong PW”。 输出样例:
1 2 3 4 5 ERROR: Not Exist New: OK ERROR: Exist ERROR: Wrong PW Login: OK
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.util.*;public class Main { public static void main (String[] args) { Map<String, String> QQNumber = new HashMap<String, String>(); Scanner scan = new Scanner(System.in); int N = scan.nextInt(); for (int i = 0 ; i < N; i++) { String order = scan.next(); String number = scan.next(); String password = scan.next(); if (Objects.equals(order, "N" )) { if (QQNumber.containsKey(number)) { System.out.println("ERROR: Exist" ); } else { QQNumber.put(number, password); System.out.println("New: OK" ); } } else { if (QQNumber.containsKey(number)) { if (!Objects.equals(QQNumber.get(number), password)) { System.out.println("ERROR: Wrong PW" ); } else { System.out.println("Login: OK" ); } } else { System.out.println("ERROR: Not Exist" ); } } } } }