[2018大華軟件創新挑戰賽] 初賽1~10題多種思路總結html
賽題以及注意事項(下載):https://files.cnblogs.com/files/usingnamespace-caoliu/%E5%88%9D%E8%B5%9B.rarnode
第一題(已優化):算法
給定一個正數數組,找出不相鄰元素的子序列的和的最大值。如:二、五、三、9應該返回14(5+9);八、五、三、九、1應該返回17(8+9);5 4 10 100 10 5應該返回110(5+100+5);數組
1 #include <stdio.h>
2 #include <unistd.h>
3
4 int max = 0; 5
6 void combination(int* arr,int i,int len) 7 { 8 if(i >= len) 9 { 10 int sum = 0; 11 for(int j=0; j<len-1; j++) 12 { 13 if(arr[j] && arr[j+1]) return; 14 sum += arr[j]; 15 } 16
17 sum += arr[len-1]; 18
19 if(sum > max) 20 { 21 max = sum; 22 } 23 return; 24 } 25
26 int tmep = arr[i]; 27 arr[i] = 0; 28 combination(arr,i+1,len); 29 arr[i] = tmep; 30 combination(arr,i+1,len); 31 } 32
33 int main() 34 { 35 int t = 0; 36 scanf("%d",&t); 37 while(t--) 38 { 39 int n = 0; 40 scanf("%d",&n); 41 int arr[n]; 42 for(int i=0; i<n; i++) 43 { 44 scanf("%d",&arr[i]); 45 } 46 combination(arr,0,n); 47 printf("%d\n",max); 48 } 49 }
思路:與大華模擬題第四題相同,利用遞歸函數遍歷數組中任意位數相加的和,再經過if(arr[j] && arr[j+1]) return;剔除全部包含相鄰元素的子序列的和,最後遍歷全部符合題意的和,比較後便可得出不相鄰元素的子序列的和的最大值。框架
總結:該方法爲通用解法而非最優解,本質爲遞歸嵌套,最終會造成一種相似於二叉樹的結構,可經過更改遞歸最後一層的斷定條件來實現絕大部分需遍歷的功能。ide
第二題(已優化):函數
給定一個鏈表,實現一個函數,將鏈表中每k個節點進行翻轉,若最後一組節點數量不足k個,則按實際個數翻轉。例如:給定鏈表1->2->3->4->5->6->7->8->NULL,k=3,翻轉後輸出3->2->1->6->5->4->8->7->NULL。
翻轉函數reverse有兩個參數,分別爲鏈表頭指針和翻轉步長k。測試
1 #include <stdio.h>
2
3 void _release(int* arr,int len) 4 { 5 for(int i=0; i<len/2; i++) 6 { 7 int t = arr[i]; 8 arr[i] = arr[len-1-i]; 9 arr[len-1-i] = t; 10 } 11 } 12
13 void release(int* arr,int k,int n) 14 { 15 if(k > n) 16 { 17 _release(arr,n); 18 return; 19 } 20 _release(arr,k); 21 release(arr+k,k,n-k); 22 } 23
24 int main() 25 { 26 int t = 0; 27 scanf("%d",&t); 28
29 while(t--) 30 { 31 int n = 0; 32 scanf("%d",&n); 33 int arr[n]; 34 for(int i=0; i<n; i++) 35 { 36 scanf("%d",&arr[i]); 37 } 38
39 int k = 0; 40 scanf("%d",&k); 41 release(arr,k,n); 42
43 for(int i=0; i<n; i++) 44 { 45 printf("%d ",arr[i]); 46 } 47 printf("\n"); 48 } 49 }
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4
5 //#include "linked_list.h"
6
7 typedef int T; 8
9 typedef struct Node 10 { 11 //節點保存的數據
12 T data; 13 //下一個節點的位置
14 struct Node* next; 15 }Node,Link; 16
17 //建立一個鏈表
18 Link* creat_link() 19 { 20 //建立一個節點,表示頭節點,該節點並不保存數據
21 Link* head = (Link*)malloc(sizeof(Node)); 22 //讓頭節點的next置NULL,表示鏈表爲空
23 head->next = NULL; 24 //返回頭的地址
25 return head; 26 } 27
28 //清空鏈表
29 void clear_link(Link* link) 30 { 31 Node* node = link->next; 32 while(node != NULL) 33 { 34 Node* tmp = node; 35 node = node->next; 36 free(tmp); 37 } 38 link->next = NULL; 39 } 40
41 //銷燬鏈表
42 void destroy_link(Link* link) 43 { 44 clear_link(link); 45 free(link); 46 link = NULL; 47 } 48
49 //判斷鏈表是否爲空
50 bool emtpy_link(Link* link) 51 { 52 return !link->next; 53 } 54
55 //得到鏈表裏元素的個數
56 size_t size_link(Link* link) 57 { 58 size_t i = 0; 59 //用node記錄頭節點的下一個位置
60 Node* node = link->next; 61 //只要node不爲NULL,表示該節點存在
62 while(node != NULL) 63 { 64 //讓node繼續指向下一個節點
65 node = node->next; 66 i++; 67 } 68 return i; 69 } 70
71 //返回下標爲index的前一個節點
72 Node* getNode_link(Link* link, int index) 73 { 74 Node* node = link; 75 //若是index=0 其前一個節點就爲link ,並不會進入下面循環
76 for(int i=0; node != NULL && i<index; i++) 77 { 78 node = node->next; 79 } 80 return node; 81 } 82
83 //更新鏈表下標爲index的節點的值
84 bool update_link(Link* link, int index, T value) 85 { 86 if(index < 0 || index > size_link(link)-1) 87 return false; 88 Node* node = getNode_link(link, index+1); 89 node->data = value; 90 return true; 91 } 92
93 //插入一個元素到指定位置 index取值範圍[0,size_link(Link* link)]
94 bool insert_link(Link* link, int index, T value) 95 { 96 if(index < 0 || index > size_link(link)) 97 return false; 98 //獲得下標爲index位置的前一個節點
99 Node* prevNode = getNode_link(link, index); 100 //申請內存,用於保存須要插入的數據
101 Node* node = (Node*)malloc(sizeof(Node)); 102 node->data = value; 103 //插入節點的下一個節點指向index前一個節點的後節點
104 node->next = prevNode->next; 105 //讓index的前節點的下一個節點指向當前插入的節點
106 prevNode->next = node; 107 return true; 108 } 109 //插入一個元素到鏈表末尾
110 bool insertBack_link(Link* link, T value) 111 { 112 return insert_link(link, size_link(link), value); 113 } 114 //插入一個元素到鏈表首部
115 bool insertFront_link(Link* link, T value) 116 { 117 return insert_link(link, 0, value); 118 } 119
120 //刪除指定下標的元素
121 bool delete_link(Link* link, int index) 122 { 123 if(index < 0 || index > size_link(link)-1) 124 return false; 125 //得到須要刪除節點的前一個節點
126 Node* prevNode = getNode_link(link, index); 127 //保存要刪除的節點,用於釋放內存
128 Node* node = prevNode->next; 129 //讓要刪除節點的前一個節點指向要刪除節點的後一個節點
130 prevNode->next = prevNode->next->next; 131 free(node); 132 return true; 133 } 134
135 //刪除元素爲value的全部節點,返回值表示該鏈表的數據是否發生變化
136 bool deleteDatas_link(Link* link, T value) 137 { 138 //做爲是否刪除成功的一個標誌
139 bool flag = false; 140 Node* node = link->next; 141 for(int i = 0; node != NULL; i++) 142 { 143 if(node->data == value) 144 { 145 delete_link(link, i); 146 //刪除後斷定下標前移
147 i--; 148 flag = true; 149 } 150 node = node->next; 151 } 152 return flag; 153 } 154
155 //刪除元素爲value的第一個元素
156 bool deleteData_link(Link* link, T value) 157 { 158 Node* node = link->next; 159 for(int i = 0; node != NULL; i++) 160 { 161 if(node->data == value) 162 //做爲是否刪除成功的一個標誌
163 return delete_link(link, i); 164 node = node->next; 165 } 166 return false; 167 } 168
169 //查找元素value的下標
170 int indexOf_link(Link* link, T value) 171 { 172 Node* node = link->next; 173 for(int i = 0; node != NULL; i++) 174 { 175 if(node->data == value) 176 return i; 177 node = node->next; 178 } 179 return -1; 180 } 181
182 //遍歷鏈表
183 void travel_link(Link* link) 184 { 185 Node* node = link->next; 186 while(node != NULL) 187 { 188 printf("%d ",node->data); 189 node = node->next; 190 } 191 puts(""); 192 } 193
194 //鏈表逆序
195 void reverse(Link link) 196 { 197 if(link == NULL || link->next == NULL) 198 return; 199 //0、記錄前一個節點與當前節點
200 Node* prevNode = link->next; 201 Node* node = prevNode->next;//NULL 202 //只要當前節點存在
203 while(node != NULL) 204 { 205 //一、先記錄當前節點的後一個節點
206 Node* nextNode = node->next; 207 //二、讓當前節點(node)的下一個節點(node->next)指向(=)前一個節點(prev)
208 node->next = prevNode; 209 //三、讓前一個節點指向當前節點、當前節點指向原先記錄的下一個節點
210 prevNode = node; 211 node = nextNode; 212 } 213 //四、讓原來的第一個元素變爲尾元素,尾元素的下一個置NULL
214 link->next->next = NULL; 215 //五、讓鏈表的頭節點指向原來的尾元素
216 link->next = prevNode; 217 } 218
219 //鏈表中每k個節點進行翻轉,若最後一組節點數量不足k個,則按實際個數翻轉。
220 void reverseByNum(Node* prev,Node* node,int num) 221 { 222 if(node == NULL) 223 return; 224 Node* prevNode = node; 225 Node* curNode = node->next; 226 int count = 1; 227 while(curNode != NULL) 228 { 229 Node* nextNode = curNode->next; 230 curNode->next = prevNode; 231 prevNode = curNode; 232 curNode = nextNode; 233 count++; 234 if(count == num) 235 { 236 Node* tmp = prev->next; 237 prev->next->next = curNode; 238 prev->next = prevNode; 239 reverseByNum(tmp,curNode,num); 240 return; 241 } 242 } 243 prev->next->next = curNode; 244 prev->next = prevNode; 245 } 246
247 void reverses(Link link,int num) 248 { 249 Node *node = link->next; 250 reverseByNum(link,node,num); 251 }
思路1:該題能夠經過數組來實現要求,按照題意將數組分割並分別翻轉便可。同時要考慮到數組沒法均分的狀況。優化
思路2:經過鏈表實現,詳見博客第三章節:[C語言]單向鏈表的構建以及翻轉算法編碼
總結:該題很簡單,留意數組沒法均分的狀況便可。
第三題(已優化):
輸入一個由大寫字母‘A-Z’組成的字符串,按照以下方式,對字符串中的字符進行編碼:
1.統計每一個字符出現的次數,並根據出現次數對字符進行權重分配;
a.出現次數越高,權重越大; b.出現次數相同,字符值越小,權重越大; c.權重值爲1~26,必須從1開始,連續分配,數值越大,權重越高;
2.把權重最小的兩個字符構成二叉樹的左右子節點,其和做爲根節點(節點值爲字符權重);
a.若兩個子節點值不等,較小值做爲左子節點;
b.若兩個子節點值相同(多字符的權重和與另外一個字符權重可能相同),則葉子節點做爲左子節點;
3.重複過程2,直到根節點值爲全部字符的權重和;
4.將樹的左邊定位0,右邊定位1,從根節點到字符節點的路徑,即爲其編碼值;
示例:
1.輸入字符串‘MBCEMAMCBA’,各字符出現次數分別爲M:3,A:2,B:2,C:2,E:1;
2.根據字符出現次數和字符大小,進行排序,結果爲:M>A>B>C>E,對應權重值爲 M:5,A:4,B:3,C:2,E:1
3.根據規則生成權重樹:
a.(M:5,A:4,B:3,C:2,E:1)中E:1和C:2值最小,相加得3,則E:1爲左節點,C:2爲右節點,3爲根節點;
b.(M:5,A:4,B:3,3)中B:3和3值最小,相加得6,則B:3爲左節點,3爲右節點,6爲根節點;
c.(M:5,A:4,6)中M:5和A:4值最小,相加得9,則A:4爲左節點,M:5爲右節點,9爲根節點;
d.(6,9)中只有兩個值,相加得15,則6爲左節點,9爲右節點,15爲根節點;
e.根節點達到全部字符的權重和1+2+3+4+5=15,結果以下:
15
0/ 1\
6 9
0/ 1\ 0/ 1\
B:3 3 A:4 M:5
0/ 1\
E:1 C:2
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 typedef struct Node 5 { 6 char ch; 7 char code; 8 int count; 9 int weight; 10 struct Node* left; 11 struct Node* right; 12 }Node; 13
14 Node* create_node(void) 15 { 16 Node* node = malloc(sizeof(Node)); 17 node->ch = 0; 18 node->weight = 0; 19 node->left = NULL; 20 node->right = NULL; 21 } 22
23 int ch_cnt = 0; 24 char arr_code[10000] = {}; 25 Node arr_node[26] = {}; 26
27 void count_weight(char* str) 28 { 29 for(int i=0,j=0; str[i]; i++) 30 { 31 for(j=0; j<ch_cnt; j++) 32 { 33 if(str[i] == arr_node[j].ch) break; 34 } 35
36 if(j<ch_cnt) continue; 37 arr_node[ch_cnt++].ch = str[i]; 38 } 39
40 for(int i=0; i<ch_cnt; i++) 41 { 42 for(int j=0; str[j]; j++) 43 { 44 if(arr_node[i].ch == str[j]) arr_node[i].count++; 45 } 46 } 47
48 for(int i=0; i<ch_cnt-1; i++) 49 { 50 for(int j=i+1; j<ch_cnt; j++) 51 { 52 if(arr_node[i].count > arr_node[j].count ||
53 (arr_node[i].count==arr_node[j].count && arr_node[i].ch < arr_node[j].ch)) 54 { 55 Node t = arr_node[i]; 56 arr_node[i] = arr_node[j]; 57 arr_node[j] = t; 58 } 59 } 60 } 61
62 for(int i=0; i<ch_cnt; i++) 63 { 64 arr_node[i].weight = i+1; 65 } 66 } 67
68 void create_tree(void) 69 { 70 if(ch_cnt<=1) return; 71
72 Node* root = create_node(); 73 root->left = create_node(); 74 root->right = create_node(); 75
76 *(root->left) = arr_node[0]; 77 *(root->right) = arr_node[1]; 78
79 root->left->code = '0'; 80 root->right->code = '1'; 81
82 root->weight += root->left->weight; 83 root->weight += root->right->weight; 84
85
86 arr_node[1] = *root; 87
88 for(int i=0; i<ch_cnt-1; i++) 89 { 90 arr_node[i] = arr_node[i+1]; 91 } 92
93 ch_cnt--; 94
95 for(int i=0; i<ch_cnt-1; i++) 96 { 97 for(int j=i+1; j<ch_cnt; j++) 98 { 99 if(arr_node[i].weight > arr_node[j].weight ||
100 (arr_node[i].weight == arr_node[j].weight&&!arr_node[i].ch)) 101 { 102 Node t = arr_node[i]; 103 arr_node[i] = arr_node[j]; 104 arr_node[j] = t; 105 } 106 } 107 } 108 create_tree(); 109 } 110 void show_tree(Node* tree) 111 { 112 if(NULL == tree) return; 113 show_tree(tree->left); 114 show_tree(tree->right); 115 } 116
117 int find_tree(Node* tree,char ch) 118 { 119 if(NULL == tree) return 0; 120 if(tree->ch == ch) 121 { 122 arr_code[ch_cnt++] = tree->code; 123 return 1; 124 } 125
126 if(find_tree(tree->left,ch) || find_tree(tree->right,ch)) 127 { 128 arr_code[ch_cnt++] = tree->code; 129 } 130 } 131
132 int main() 133 { 134 int t = 0; 135 scanf("%d",&t); 136 char str[t][1000]; 137 for(int i=0; i<t; i++) 138 { 139 gets(str[i]); 140 } 141 for(int i=0; i<t; i++) 142 { 143 count_weight(str[i]); 144 create_tree(); 145 for(int j=0; str[i][j]; j++) 146 { 147 ch_cnt = 0; 148 find_tree(arr_node,str[i][j]); 149 for(int k=ch_cnt-1; k>=0; k--) 150 { 151 printf("%c",arr_code[k]); 152 } 153 } 154 } 155
156 }
方向:此題與哈夫曼樹相關(哈夫曼樹:https://blog.csdn.net/move_now/article/details/53398753)
思路一:以哈夫曼樹爲主體,在此基礎上添加對字符串中各個字符分配權重的功能,最後分解字符串,根據各個字符的權重依次輸出路徑。
思路二:以每類字符爲主體,建立儲存各種字符信息的結構體,計算出各個字符的權重,延伸出兩個空子葉,在此基礎上根據各個字符的權重、按照題目規則將其鏈接成哈夫曼樹形結構,最後分解字符串,根據各個字符的權重依次輸出路徑。
總結:總的來講,思路一是在現有哈夫曼樹框架下進行代碼的修改、添加,輪子已經造好,咱們直接拿來用便可,能極大地減小實際代碼量,但修改現有哈夫曼樹代碼時容易打亂自身思路且缺乏創造性;思路二是以每類字符爲主體,能在編寫其結構體時有效的整理思路,整個程序關聯性強,富有創造力,但程序難度較大。
PS :該程序本地測試無誤,但上傳後一直爲0分,未能查明緣由。
第四題(未優化):
實現find_sub_string(str1,str2)函數,判斷字符串str2在str1中出現的次數。返回str2在str1中出現的次數。
int find_sub_string(const std::string& str1, const string& str2);
1 #include <stdio.h>
2 #include <string.h>
3
4 int find_sub_string(char* str1, char* str2) 5 { 6 int count = 0,i2 = 0; 7 if(*str2 && *str1) 8 { 9 for(int i=0; *(str1+strlen(str2)+i-1); i++) 10 { 11 for(int j=i; *(str1+j); j++) 12 { 13 if(*(str1+j) == *(str2+i2)) 14 { 15 if(strlen(str2)-1 == i2) 16 { 17 count++; 18 i2 = 0; 19 break; 20 } 21 else i2++; 22 } 23 else
24 { 25 i2 = 0; 26 break; 27 } 28 } 29 } 30 } 31 else return count; 32 } 33
34 int main() 35 { 36 int t; 37 scanf("%d",&t); 38 int x = t; 39 int a[t]; 40
41 while(x--) 42 { 43 char str1[10][1000] = {}; 44 char str2[10][1000] = {}; 45 scanf("%s",str1[x]); 46 scanf("%s",str2[x]); 47 printf("%d\n",find_sub_string(str1[x], str2[x])); 48 } 49 }
思路:思路簡單,循環嵌套。
總結:該題可利用庫函數實現。
第五題:
有一個吃金幣遊戲:
1.地圖中有N個城堡(編號分別爲0~N-1),每一個城堡中掛着一面旗子;
2.某些城堡之間是連通的,在其連通的路上,分散着若干個金幣(個數可能相同,也可能不一樣);
3.玩家走過存在金幣的路以後,能夠得到這條路上的全部金幣,11同一條路走屢次,只有第一次可得到金幣;
遊戲規則:
1.玩家能夠從任意一個城堡出發;
2.玩家必須拿到全部城堡的旗子;
3.玩家走過的全部路,不能存在環路;
4.必定存在至少一條能讓玩家拿到全部旗子的路線;
請設計一個算法,計算在遵照以上游戲規則的的前提下,最多能獲取到的金幣個數。
補充規則中對環路的說明:
一、環路就是最終走過的路徑中存在圈,實例以下:
非環路: 環路:1-2-5-4-1則成爲環路
1----2 3 1----2----3
| | | |
| | | |
4----5----6 4----5----6
| | | | |
| | | | |
7 8 9 7 8----9
二、如說明1中的路徑,玩家走1-2-5-4-7-4-5,雖然無圈,可是4-七、5-4中的路徑金幣只能吃一次,重複走第二次金幣不能夠獲取
第六題(未優化):
在H.264視頻編碼標準中,編碼幀由NALU頭和NALU主體組成,其中NALU頭由一個字節組成。在實際編碼時,在每一個NAL前添加起始碼 0x000001,解碼器在碼流中檢測到起始碼,當前NAL結束。
爲了防止NAL內部出現0x000001的數據,在編碼完一個NAL時,若是檢測出有連續兩個0x00字節,就在後面插入一個0x03。
當解碼器在NAL內部檢測到0x000003的數據,就把0x03拋棄,恢復原始數據。給定一組包含SPS NALU的編碼數據,找出解碼後的SPS數據。好比:
輸入:{0x1f 0x00 0x00 0x01 0x67 0x42 0xd0 0x80 0x00 0x00 0x03 0x00 0x80 0x00 0x0f 0x00 0x00 0x01 0x68 0xce 0x3c 0x80},
處理:在上述例子中,第一個0x00 0x00 0x01爲識別到的數據頭,0x00 0x00 0x03 0x00數據中,0x03爲需拋棄數據,第二個0x00 0x00 0x01爲下一個數據頭,那麼取出兩個數據頭中間的數據而且拋棄掉此0x03,結果以下:{0x67 0x42 0xd0 0x80 0x00 0x00 0x00 0x80 0x00 0x0f }。
1 #include <stdio.h>
2 #include <string.h>
3
4 void find_sps_in_h264(unsigned int* num, int len) 5 { 6 unsigned int n[50] = {}; 7 for(int i=2; i<len; i++) 8 { 9 if(num[i-2]==0x00 && num[i-1]==0x00 && num[i]== 0x01) 10 { 11 for(int j=2; i<len-1; j++) 12 { 13 n[j] = num[++i]; 14 if(j>=4 && n[j-2]==0x00 && n[j-1]==0x00 && n[j]== 0x01) 15 { 16 for(int k=2; k<j-2; k++) 17 { 18 if(k>=4 && n[k-2]==0x00 && n[k-1]==0x00 && n[k]== 0x03) 19 { 20 continue; 21 } 22 else printf("%x ",n[k]); 23 } 24 puts(""); 25 return; 26 } 27 else if(i == len-1) 28 { 29 for(int k=2; k<=j; k++) 30 { 31 if(k>=4 && n[k-2]==0x00 && n[k-1]==0x00 && n[k]== 0x03) 32 { 33 continue; 34 } 35 else printf("%x ",n[k]); 36 } 37 puts(""); 38 return; 39 } 40 } 41 } 42 } 43 } 44
45 int main() 46 { 47 int t; 48 scanf("%d",&t); 49
50 int len; 51 unsigned int num[51] = {}; 52 for(int i=0; i<t; i++) 53 { 54 scanf("%d",&len); 55 if(len<7) len = 7; 56 else if(len>50) len =50; 57 for (int j=0; j<len; j++) 58 { 59 scanf("%x",&num[j]); 60 } 61 find_sps_in_h264(num,len); 62 } 63 return 0; 64 }
思路:經過識別編碼「0x00 0x00 0x01」從碼流中取出兩個數據頭中間的數據,再將數據中「0x00 0x00 0x03」中的編碼「0x03」去除。
總結:能夠將須要重複使用的功能模塊進行函數封裝,優化代碼,提升代碼簡潔性與可閱讀性。如:斷定數據頭的功能模塊。
第七題(已優化):
給定一個全小寫的英文字符串,請在該字符串中找到一個連續子字符串,使得子字符串沒有重複的字符而且長度最長,計算此最長字符串的長度。好比:abcbdeab,最長的子字符串爲cbdea,長度爲5;aaaa,最長子字串爲a,長度爲1。
1 #include <stdio.h>
2
3 int longest_substr(char* str) 4 { 5 int longest = 0; 6 for(int i=0,j=0; str[i]; i++) 7 { 8 for(j=i+1; str[j]; j++) 9 { 10 int flag = 0; 11 for(int k=j-1; k>=i; k--) 12 { 13 if(str[j] == str[k]) flag = 1; 14 } 15
16 if(flag) break; 17 } 18 int len = j - i; 19 if(len > longest) longest = len; 20 } 21 return longest; 22 } 23
24 int main() 25 { 26 int n = 0; 27 scanf("%d",&n); 28 char str[n][101]; 29
30 for(int i=0; i<n; i++) 31 { 32 stdin->_IO_read_ptr = stdin->_IO_read_end; 33 gets(str[i]); 34 } 35
36 for(int i=0; i<n; i++) 37 { 38 printf("%d\n",longest_substr(str[i])); 39 } 40 }
思路:思路簡單,循環嵌套。
總結:三層for循環嵌套之間的關係要理清。
第八題(已優化):
一個數能夠用二進制表示,也能夠用十進制表示,若是該數的二進制表示法全部位數字之和等於十進制表示法全部位數字之和,則稱該數爲神奇數。好比:21(十進制)=10101(二進制),全部位數之和爲2+1=3,1+0+1+0+1=3。求小於等於M的神奇數有多少個。
1 #include <stdio.h>
2
3 int is_magical(int num) 4 { 5 int sum1 = 0; 6 for(int i=0; i<32; i++) 7 { 8 sum1 += (num>>i)&1; 9 } 10
11 int sum2 = 0; 12 while(num) 13 { 14 sum2 += num%10; 15 num /= 10; 16 } 17
18 return sum1 == sum2; 19 } 20
21 int main() 22 { 23 int cnt = 0; 24 scanf("%d",&cnt); 25 int m[cnt]; 26
27 for(int i=0; i<cnt; i++) 28 { 29 scanf("%d",&m[i]); 30 } 31
32 for(int i=0; i<cnt; i++) 33 { 34 int n = 0; 35 for(int j=1; j<=m[i]; j++) 36 { 37 is_magical(j) && n++; 38 } 39 printf("%d\n",n); 40 } 41 }
思路:思路簡單,考點主要在於對二進制數據的應用。
總結:二進制全部位數之和可以使用用語句 for(int i=0; i<32; i++) sum1 += (num>>i)&1; 計算。
第九題(未優化):
咱們來玩一個大富翁的遊戲,在地圖上有N個連續的城市,城市對某件商品的售價爲[V1,V2,V3...VN],你做爲將來的大富翁看到其中的商機,打起了倒賣商品賺取差價的主意。約束條件:你只能順序從第一個城市出發,不能走回頭路,每次只能交易一件商品,再下次買入商品後必須賣掉以前買入的商品,求你能賺取的最大財富。好比:城市商品售價爲[1,9,2,3,8],最大財富爲(9-1)+(8-2)=14;城市商品售價爲[9,8,3,2,1],最大財富爲0,由於你買啥都沒法賺錢。
1 #include <stdio.h>
2 #include <string.h>
3
4 int min; 5 int max; 6 int a; 7
8 int x(int* val) 9 { 10 int sum = 0; 11 int i = 0; 12 int m = max, n = min; 13 while(val[i]) 14 { 15 if(val[i] < val[i+1]) 16 { 17 min = i++; 18 while(val[i] < val[i+1] && val[i]) 19 { 20 i++; 21 } 22 max = i++; 23 sum += val[max]-val[min]; 24 } 25 else i++; 26 } 27 return sum; 28 } 29
30 int main() 31 { 32 int t; 33 scanf("%d",&t); 34
35 int val[10][100] = {}; 36 for(int i=0; i<t; i++) 37 { 38 scanf("%d",&a); 39 for (int j=0; j<a; j++) 40 { 41 scanf("%d",&val[i][j]); 42 } 43 } 44 for(int i=0; i<t; i++) 45 { 46 printf("%d\n",x(val[i])); 47 } 48 }
思路一:直接比較當前城市售價與下一城市售價,若下一城市售價高於當前城市售價,則對兩者的差值進行累加,遍歷城市後便可得到最大財富。
思路二:尋找不一樣城市售價的「拐點」,遍歷城市將全部彼此鄰近的「最高拐點」與「最低拐點」的差值進行累加,便可得到最大財富。
總結:總的來講,思路一簡單粗暴,代碼簡單、極易實現,但相比思路二會進行更多的加法運算;思路二理論上算法更優,但在該題中沒法體現其優點。
第十題(已優化):
假設你站在一棵二叉樹的右邊,從上往下,請輸出你看到的節點。好比:
5 <---
/ \
2 3 <---
/ / \
4 6 8 <---
返回 538。
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 static int index = 0; 5
6 typedef struct Node 7 { 8 char ch; 9 struct Node* left; 10 struct Node* right; 11 }Node; 12
13 Node* create_node(char ch) 14 { 15 Node* node = malloc(sizeof(Node)); 16 node->ch = ch; 17 node->left = NULL; 18 node->right = NULL; 19 } 20
21 void create_tree(Node** tree,char* str) 22 { 23 if('\0'==str[index]) return; 24
25 if(str[index] == '#') 26 { 27 *tree = NULL; 28 return; 29 } 30 *tree = create_node(str[index]); 31 if(str[index+1]) 32 { 33 index++; 34 create_tree(&(*tree)->left,str); 35 } 36
37 if(str[index+1]) 38 { 39 index++; 40 create_tree(&(*tree)->right,str); 41 } 42 } 43
44 void show_tree(Node* tree) 45 { 46 if(NULL == tree) return; 47 printf("%c\n",tree->ch); 48 show_tree(tree->right); 49 } 50
51 int main() 52 { 53 int t = 0; 54 scanf("%d",&t); 55 char str[t][1000]; 56 for(int i=0; i<t; i++) 57 { 58 gets(str[i]); 59 } 60 for(int i=0; i<t; i++) 61 { 62 index = 0; 63 Node* tree = NULL; 64 create_tree(&tree,str[i]); 65 show_tree(tree); 66 } 67 }
思路:思路簡單,考點主要在於構建二叉樹。
總結:該題有一個小坑,多心的解題人可能會考慮到:若上圖中的6存在子葉x,那麼「從上往下、從右往左」看的時候是否會「看」到x?若將這種可能性考慮進去,代碼的複雜程度提升數十倍的同時會致使該題考察點不明確,考察者沒有這麼作的意義。實際上這種可能性不屬於該題的考察點,考慮過多反而容易誤解題意。
實現效果: