PAT天梯赛Level2题目题解汇总
生活随笔
收集整理的這篇文章主要介紹了
PAT天梯赛Level2题目题解汇总
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
L2-001 緊急救援
/******************************************************************************* Date: 2018/2/2 Author: Wen Yaxin題目簡介:需要求S到D最短路徑的條數(shù),多條最短路徑的條件上, 需要輸出救援人數(shù)最多的那條。輸出最大的救援人數(shù),并把 相應(yīng)的路徑輸出。解題思路:好題,最短路變形,首先求最短路,如果最短路徑 相同,則看經(jīng)過另一個點能否增多救援人數(shù),可以的化,照樣 更新對應(yīng)的路徑。代碼變量含義: Map : 圖 path:存放路徑,path[i]存放節(jié)點i的前驅(qū)。 vis :標記節(jié)點是否已經(jīng)求出最短路徑,vis[i]=1已求出最短路 pathNum:pathNum[i]是源點S到頂點i最短路徑的條數(shù) num :存放每個節(jié)點的救援人數(shù) dist:存放源點到每個節(jié)點的最短路徑長度。 people:存放源點到當前節(jié)點的路徑中所有救援人員的總?cè)藬?shù) *********************************************************************************/#include <stdio.h> #include <iostream> #include <stack> using namespace std;const int maxn = 502; const int inf = 0x3f3f3f3f; int N,M,S,D; int Map[maxn][maxn]; int path[maxn],vis[maxn],pathNum[maxn]; int num[maxn],dist[maxn],people[maxn]; //每個城市救援隊的數(shù)目 void initMap() {for(int i = 0; i < N; i++) {for(int j = 0; j < N; j++) {if(i == j) Map[i][j] = 0;else Map[i][j] = inf;}} } void dijkstra() {people[S] = num[S];vis[S] = 1;dist[S] = 0;pathNum[S] = 1;path[S] = -1;for(int i = 0; i < N; i++) {dist[i] = Map[S][i];if(Map[S][i]<inf && i != S) {people[i] = num[i]+num[S];pathNum[i] = 1;path[i] = S;}}int u,mindis;for(int i = 1; i < N; i++) {mindis = inf;u = S;for(int j = 0; j < N; j++) {if(vis[j]==0 && dist[j]<mindis) {u = j;mindis = dist[j];}}vis[u] = 1;for(int j = 0; j < N; j++) {if(vis[j]==0 && Map[u][j]<inf) {if(dist[u]+Map[u][j]<dist[j]) {pathNum[j] = pathNum[u];path[j] = u;dist[j] = dist[u] + Map[u][j];people[j] = people[u] + num[j];}else if(dist[u]+Map[u][j] == dist[j]) {pathNum[j] += pathNum[u];if(people[u]+num[j]>people[j]) {people[j] = people[u] + num[j];path[j] = u;}}}}} } void printAns() {printf("%d %d\n",pathNum[D],people[D]);stack<int>st;st.push(D);while(path[D] != -1) {D = path[D];st.push(D);}printf("%d",st.top());st.pop();while(!st.empty()) {printf(" %d",st.top());st.pop();}printf("\n"); } int main() {while(~scanf("%d%d%d%d",&N,&M,&S,&D)) {initMap();for(int i = 0; i < N; i++) {scanf("%d",&num[i]);}int u,v,len;for(int i = 0; i < M; i++) {scanf("%d%d%d",&u,&v,&len);if(len < Map[u][v]) {Map[u][v] = Map[v][u] = len;}}dijkstra();printAns();}return 0; }L2-002 鏈表去重
/********************************************************************************** Date: 2018/2/2 20:57 Author: Wen Yaxin題目簡介:將鏈表中絕對值重復(fù)的元素去除,原鏈表形成一個新 鏈表,被刪除的元素組成一個新鏈表,先輸出去重后的鏈表,再 輸出被去重的元素組成的鏈表。注意鏈表中刪除元素后,其下 一個指向會變。解題思路:對于一個節(jié)點維護本身的值,然后存放下一個元素的 值,然后從表頭開始遍歷鏈表,如果其節(jié)點值的絕對值沒有出現(xiàn) 過,將該節(jié)點的地址放入數(shù)組1,并標記該節(jié)點的值,否則將地址 放入節(jié)點2。代碼變量含義: vis :標記數(shù)組,用來標記絕對值為i的值有沒有出現(xiàn)過 arr1:存放去重后的鏈表的節(jié)點所在的地址。 arr2:存放被刪除的節(jié)點所在的地址 node:維護一個個鏈表節(jié)點 *************************************************************************************/ #include <stdio.h> #include <iostream> #include <cmath> #include <string.h>using namespace std;const int maxn = 1e5+10; int vis[maxn],arr1[maxn],arr2[maxn]; struct Node {int value; //值int nex; //下個節(jié)點的坐標 }node[maxn]; int main() {int start,address,key,nex,num;while(~scanf("%d%d",&start,&num)) {memset(vis,0,sizeof(vis));for(int i = 0; i < maxn; i++) {node[i].nex = -1;}for(int i = 0; i < num; i++) {scanf("%d%d%d",&address,&key,&nex);node[address].value = key;node[address].nex = nex;}int cnt1=0,cnt2=0;while(start != -1) {key = node[start].value;int temp = abs(key);if(vis[temp] == 0) {vis[temp] = 1;arr1[cnt1++] = start;}else {arr2[cnt2++] = start;}start = node[start].nex;}for(int i = 0; i < cnt1; i++) {int temp = arr1[i];if(i != cnt1-1)printf("%05d %d %05d\n",temp,node[temp].value,arr1[i+1]);elseprintf("%05d %d -1\n",temp,node[temp].value);}for(int i = 0; i < cnt2; i++) {int temp = arr2[i];if(i != cnt2-1)printf("%05d %d %05d\n",temp,node[temp].value,arr2[i+1]);elseprintf("%05d %d -1\n",temp,node[temp].value);}}return 0; }L2-003 月餅
/***************************************************** Date: 2018/2/4 20:16 Author: Wen Yaxin解題思路:求出每種月餅的單價,按照單價從大到小排序。 然后從貴的月餅開始買即可。變量含義: node:維護每種的月餅的總重,總價和單價。 ******************************************************/ #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h>using namespace std;struct Node {double weight; //總庫存量double allMoney; //總價格double price; //單價 }node[1002]; bool cmp(Node a,Node b) {return a.price>b.price; } int main() {int n,d;while(~scanf("%d%d",&n,&d)) {for(int i = 0; i < n; i++) {scanf("%lf",&node[i].weight);}for(int i = 0; i < n; i++) {scanf("%lf",&node[i].allMoney);node[i].price = node[i].allMoney/node[i].weight;}sort(node,node+n,cmp);double sum = 0;for(int i = 0; i < n; i++) {if(d >= node[i].weight) {sum = sum + node[i].allMoney;d = d - node[i].weight;}else {sum = sum + d*node[i].price;break;}}printf("%.2lf\n",sum);}return 0; } L2-004 這是二叉搜索樹嗎? /************************************************************************ Date: 2018/2/4 21:19 Author: Wen Yaxin題目簡介:給出一個序列,判斷該樹是否是二叉搜索樹或其鏡像樹的 前序序列。如果是輸出YES和該樹的后續(xù)序列,否則輸出NO。解題思路:該題采用逆向思維,如果熟知二叉搜索樹的建樹法則, 變可對序列進行建樹,首先對給出的序列建立二叉搜索樹以及其鏡像 樹,然后對這兩顆樹進行先序遍歷,如果遍歷出的序列和題目中給出 的序列相同,則說明題目給出的序列的確是二叉搜索樹的先序序列。 否則說明題目給出的序列不是二叉搜索樹的先序序列。然后對樹求 后續(xù)。變量含義: node: 二叉搜索樹節(jié)點 node->key:節(jié)點對應(yīng)的值 node->lchild:左孩子節(jié)點 node->rchild:右孩子節(jié)點 **************************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<stdlib.h> #include<stack>using namespace std;int a[100000],b[1000000],n,flag; typedef struct node {int key;struct node *lchild,*rchild; }BSTNode; //根據(jù)序列構(gòu)建正常樹 int InsertBST1(BSTNode *&p,int k) {if(p == NULL){p = (BSTNode*)malloc(sizeof(BSTNode));p->key = k;p->lchild = p->rchild = NULL;return 1;}else if(k < p->key)return InsertBST1(p->lchild,k);elsereturn InsertBST1(p->rchild,k); } //根據(jù)序列構(gòu)建鏡面樹 int InsertBST2(BSTNode *&p,int k) {if(p == NULL){p = (BSTNode*)malloc(sizeof(BSTNode));p->key = k;p->lchild = p->rchild = NULL;return 1;}else if(k < p->key)return InsertBST2(p->rchild,k);elsereturn InsertBST2(p->lchild,k); } //求樹的先序序列 void PreOrder(BSTNode *bt) {stack<BSTNode*>st;BSTNode *p;int k = 0;if(bt!=NULL){st.push(bt);while(!st.empty()){p = st.top();st.pop();b[k++] = p->key;if(p->rchild!=NULL)st.push(p->rchild);if(p->lchild!=NULL)st.push(p->lchild);}} } //求樹的后續(xù)序列 void PostOrder(BSTNode *bt) {if(bt!=NULL){PostOrder(bt->lchild);PostOrder(bt->rchild);if(flag){printf("%d",bt->key);flag = 0;}elseprintf(" %d",bt->key);} } //判斷給出的序列是否是正常樹或鏡面樹的先序序列 void IsRight(BSTNode *bt1,BSTNode *bt2) {int state1 = 1,state2 = 1,i;flag = 1;PreOrder(bt1); //對正常樹進行先序遍歷for(i = 0; i < n; i++)if(a[i]!=b[i]){state1 = 0;break;}if(state1){printf("YES\n");PostOrder(bt1);printf("\n");return;}flag = 1;PreOrder(bt2);for(i = 0; i < n; i++)if(a[i]!=b[i]){state2 = 0;break;}if(state2){printf("YES\n");PostOrder(bt2);printf("\n");return;}printf("NO\n");return; } int main() {int i;while(~scanf("%d",&n)){BSTNode *bt1 = NULL; //正常樹樹根BSTNode *bt2 = NULL; //鏡面樹樹根for(i = 0; i < n; i++){scanf("%d",&a[i]);InsertBST1(bt1,a[i]); //構(gòu)建正常樹InsertBST2(bt2,a[i]); //構(gòu)建鏡面樹}IsRight(bt1,bt2);}return 0; } L2-005 集合相似度 /***************************************************** Date: 2018/2/4 21:39 Author: Wen Yaxin解題思路:用stl中的set來解思路很簡單,提問集合 s1和s2的相似度, 本來的想法是將s1中的元素放入set1中,將s2中的元素放入set2中, 這樣調(diào)用size函數(shù)就可以求出s1中不同元素的個數(shù),以及s2中不同元素 的個數(shù),然后再將s1和s2放到一個set3里面,是兩個集合中不同元素的 個數(shù)。因此:NC = set1.size()+set2.size()-set3.size(); NT = set3.size(); ******************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<set> #define INF 1000 #define max(a,b) a>b? a:busing namespace std;set<int>Set[100002]; int main() {int N,M,K;int s1,s2,temp;while(~scanf("%d",&N)){for(int i = 1; i <= N; i++){scanf("%d",&M);if(!Set[i].empty()) // 如果第i個集合非空,清空Set[i].clear();for(int j = 1; j <= M; j++){scanf("%d",&temp);Set[i].insert(temp); //將temp插入到集合i}}scanf("%d",&K); //接下來會詢問K個集合的相似度while(K--){scanf("%d%d",&s1,&s2); //求集合1和集合2的相似度set<int>::iterator it;int count = 0; //用來存放兩個集合都有的不同元素的個數(shù)for(it = Set[s1].begin(); it != Set[s1].end(); it++){if(Set[s2].count(*it)) //如果*it在集合2中count++;}int nt = Set[s1].size()+Set[s2].size()-count;double ans = (count*1.0)/nt*100;printf("%.2lf%%\n",ans);}}return 0; }L2-006 樹的遍歷
/************************************************************************************** Date: 2018/2/5 18:59 Author: Wen Yaxin解題思路:對于二叉樹,如果只給出先序遍歷序列,中序遍歷序列或后續(xù)遍歷 序列,是不能確定二叉樹的樹形的,在李春保的數(shù)據(jù)結(jié)構(gòu)書的樹這一數(shù)據(jù)結(jié)構(gòu) 這一章畫有若干圖表明了這一結(jié)論,但是給出先序+中序或給出后序+中序可以 確定二叉樹的形狀,因此對于本題給出的后序和中序是可以確定唯一一顆二叉 樹的,對于后序,其遍歷順序是左右根,因此可知給出的序列中的最后一個元素 便是根節(jié)點,根據(jù)該根節(jié)點在中序中查找到該節(jié)點,由于中序的遍歷順序是左根 右,因此節(jié)點左側(cè)序列是其左子樹的中序遍歷,右側(cè)是其右子樹的中序遍歷。變量解釋: post:后序序列 in:中序序列 node:二叉樹節(jié)點 *p:輔助指針,在查找in數(shù)組的時候,指向查找到的位置 *b:建立二叉樹節(jié)點用的輔助指針 r:當前后序序列的最后一個值,即當前后序、中序?qū)?yīng)的根節(jié)點。 **************************************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<stdlib.h> #include<stack> #include<set> #include<queue>using namespace std;int n; int post[50],in[50]; typedef struct node {int data;struct node *lchild;struct node *rchild; }BTNode; BTNode* CreateTree(int *post,int *in,int n) {BTNode *b; //建立節(jié)點用的輔助指針int r,*p;int k;if(n <= 0) return NULL;r = *(post+n-1); //初始指向最后后序最后一個元素b = (BTNode*)malloc(sizeof(BTNode));b->data = r;//在中序中查找該元素。for(p = in; p < in+n; p++){if(*p == r) break;}k = p-in; //找到中序中對應(yīng)元素的下標//in數(shù)組k左側(cè)都屬于當前接待你的左子樹b->lchild = CreateTree(post,in,k);//post+k后和p+1后分別是當前右字數(shù)的后序和中序。b->rchild = CreateTree(post+k,p+1,n-k-1);return b; } void LevelOrder(BTNode *b) {queue<BTNode*>qu;BTNode *p;p = b;if(p!=NULL) //if it isn't a empty tree{qu.push(p); //first put the root into queue}int flag = 1;while(!qu.empty()){p = qu.front();qu.pop();if(flag){printf("%d",p->data);flag = 0;}elseprintf(" %d",p->data);if(p->lchild!=NULL)qu.push(p->lchild);if(p->rchild!=NULL)qu.push(p->rchild);}printf("\n"); } int main() {while(~scanf("%d",&n)){for(int i = 0; i < n; i++)scanf("%d",&post[i]);for(int i = 0; i < n; i++)scanf("%d",&in[i]);BTNode *bt;bt = CreateTree(post,in,n);LevelOrder(bt);}return 0; } L2-007 家庭房產(chǎn) /******************************************************************************************* Date: 2018/2/5 21:00 Author: Wen Yaxin題目簡述:給出N,然后給出N個人的房產(chǎn)情況。數(shù)據(jù)組織情況如下。 個人編號,父親編號,母親編號,這個人的孩子個數(shù), 然后給出這個人孩子的編號,然后給出個人的房產(chǎn)套數(shù),這些房產(chǎn)的總面積。 父親母親編號為-1代表父親母親過世。解題思路:并查集加排序。每一個人的編號維護一個集合,對于給出的一組 數(shù)據(jù),涉及到的所有人員的編號都必須進行集合合并操作,集合合并的準則 是以編號小的人集合為準,因為答案要的家族代表是該家族中的最小編號, 對于每一個集合,我們需要維護該集合中的人數(shù),該集合的房子套數(shù),該集合 的房子總面積,通過查找元素所屬集合,假如查找出兩個元素分別在x集合,y集合 如果x和y相等,不需要合并,否則合并到編號較小的集合中,并且把另一個集合 的所有資源也都合并過去。由于給出的人員編號不連續(xù),因此用vis數(shù)組進行標記, 將題目中所出現(xiàn)的所有編號都存儲起來(vis標記是為了讓編號不被重復(fù)存儲), 然后通過這些編號去查找有多少集合,并把這些家庭存儲起來進行排序。最后輸出。變量解釋: N:代表將給出N個人的房產(chǎn)情況 f: f[i]中存放編號為i的人所在的集合編號 houseNum:houseNum[i]代表以i為編號的家族的房產(chǎn)數(shù) houseArea:houseArea[i]代表以i為編號的家族的房產(chǎn)總面積 people:people[i]代表以i為編號的家族的人數(shù) vis:vis[i]用來標記編號為i的人有沒有被放入容器中 vector:v用來存儲題目中出現(xiàn)過的人員編號 ***********************************************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<stdlib.h> #include<stack> #include<set> #include<vector>using namespace std;const int maxn = 1e5+10; int N,f[maxn],houseNum[maxn],houseArea[maxn],people[maxn]; int vis[maxn]; vector<int>v; struct Node {int index; //編號int familys; //家人個數(shù)double averNum; //人均房產(chǎn)套數(shù)double averArea; //人均房產(chǎn)面積 }node[maxn]; //初始化集合 void initSet() {for(int i = 0; i < maxn; i++) {f[i] = i;houseNum[i] = 0;houseArea[i] = 0;people[i] = 1;} } //查找某個人所在的家族編號 int findSet(int x) {while(x != f[x]) {x = f[x];}return x; } //合并集合,規(guī)則是往編號小的集合合并 void unionSet(int x,int y) {if(x != y) {//并到xif(x < y) {f[y] = x;people[x] += people[y];houseNum[x] += houseNum[y];houseArea[x] += houseArea[y];} //集合并到y(tǒng)else {f[x] = y;people[y] += people[x];houseNum[y] += houseNum[x];houseArea[y] += houseArea[x];}} } //對每組數(shù)據(jù)進行處理 void handle() {int my,father,monther,childNum,num,area,childId;int s1,s2,s3;scanf("%d%d%d%d",&my,&father,&monther,&childNum);if(!vis[my]) {v.push_back(my);vis[my] = 1;}if(father != -1) {if(!vis[father]) {v.push_back(father);vis[father] = 1;}}if(monther != -1) {if(!vis[monther]) {v.push_back(monther);vis[monther] = 1;}}s1 = findSet(my);if(father != -1) {s2 = findSet(father);unionSet(s1,s2);}s1 = findSet(my);if(monther != -1) {s3 = findSet(monther);unionSet(s1,s3);}while(childNum--) {scanf("%d",&childId);if(!vis[childId]) {v.push_back(childId);vis[childId] = 1;}s1 = findSet(my);s2 = findSet(childId);unionSet(s1,s2);}s1 = findSet(my);scanf("%d%d",&num,&area);houseNum[s1] += num;houseArea[s1] += area; } //排序用的構(gòu)造函數(shù) bool cmp(Node a,Node b) {//人均面積相等,按照編號對其進行升序排列if(fabs(a.averArea-b.averArea)<1e-4) {return a.index<b.index;}else {return a.averArea>b.averArea;} } int main() {while(~scanf("%d",&N)) {v.clear(); //清空vectorinitSet(); //集合初始化memset(vis,0,sizeof(vis));while(N--) {handle();}int cnt = 0;for(int i = 0; i < (int)v.size(); i++) {int id = v[i];if(f[id] == id) {node[cnt].index = id;node[cnt].familys = people[id];node[cnt].averNum = (houseNum[id]*1.0)/people[id];node[cnt++].averArea = (houseArea[id]*1.0)/people[id];}}sort(node,node+cnt,cmp);printf("%d\n",cnt);for(int i = 0; i < cnt; i++) {printf("%04d %d %.3lf %.3lf\n",node[i].index,node[i].familys,node[i].averNum,node[i].averArea);}}return 0; }L2-008 最長對稱子串
/*************************************************************************************** Date: 2018/3/10 9:25 Author: Wen Yaxin解題思路:對每個字符進行枚舉,分別考慮它作為奇數(shù)串中心的字符,和偶數(shù)串中心 的字符,然后從該字符向左向右擴展。尋找最長對稱串。變量含義: str:存放題目給出的字符串。 *******************************************************************************************/ #include <iostream> #include <stdio.h> #include <string.h>using namespace std;char str[1005]; int main() {while(gets(str)) {int len = strlen(str);int maxLen = 0,j;for(int i = 0; i < len; i++) {//求以i為中心的奇數(shù)串。j = 0;while(i-j-1>=0 && i+j+1<len) {if(str[i-j-1] == str[i+j+1]) {j++;}else {maxLen = max(maxLen,2*j+1);break;}}maxLen = max(maxLen,2*j+1);while(i-j-1>=0 && i+j<len) {if(str[i-j-1] == str[i+j]) {j++;}else {maxLen = max(maxLen,2*j);break;}}maxLen = max(maxLen,2*j);}printf("%d\n",maxLen);}return 0; }L2-009 搶紅包
/************************************************************************** Date: 2018/3/10 10:21 Author: Wen Yaxin解題思路:一個人收益等于它搶到的錢-它發(fā)出去的錢。對于某個人發(fā)的紅包, 使用數(shù)組標記防止搶過紅包的人重復(fù)領(lǐng),最后排序輸出。變量含義: vis:用來對搶過某個人紅包的人做標記 node:維護人的編號,搶紅包的收益,搶到紅包的數(shù)量。方法含義: init:對結(jié)構(gòu)體數(shù)組進行初始化 cmp:排序所使用的構(gòu)造函數(shù) ***************************************************************************/ #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm>using namespace std;const int maxn = 1e4+5; int vis[maxn]; struct Node {int index;int num;double money; }node[maxn]; void init(int n) {for(int i = 1; i <= n; i++) {node[i].index = i;node[i].money = 0;node[i].num = 0;} } bool cmp(Node a,Node b) {if(a.money == b.money) {if(a.num == b.num) {return a.index < b.index;}else {return a.num > b.num;}}else {return a.money > b.money;} } int main() {int N,K,M,P;while(~scanf("%d",&N)) {init(N);for(int i = 1; i <= N; i++) {scanf("%d",&K);memset(vis,0,sizeof(vis));while(K--) {scanf("%d%d",&M,&P);if(!vis[M]) {vis[M] = 1;node[M].money += P;node[i].money -= P;node[M].num++;}}}sort(node+1,node+1+N,cmp);for(int i = 1; i <= N; i++) {printf("%d %.2lf\n",node[i].index,node[i].money/100);}}return 0; }L2-010 排座位
/****************************************************************************************** Date: 2018/3/10 10:58 Author: Wen Yaxin解題思路:用并查集來確定朋友關(guān)系,并用容器來存放每個人的敵人。 1.如果兩個人是朋友,且他們不在一個集合,對集合進行合并。因為朋友的朋友也是朋友。 2.如果x,y兩個人是敵人,則把y放入x的容器,把x放入y的容器。 3.對于詢問,如果查明x,y在同一集合,則說明二者是朋友。此時在容器中查找是否敵對。 (1) x,y在同一集合,且x對應(yīng)的容器中存有y。屬于有共同朋友,又彼此敵對。輸出"OK but..."; (2) x,y在同一集合,且x對應(yīng)的容器中沒有y。屬于朋友關(guān)系,且不敵對,輸出"No problem"; (3) x,y在不同集合,且x對應(yīng)的容器中存有y。二者不是朋友,且敵對。輸出"No way"; (4) x,y在不同集合,且x對應(yīng)的容器中沒有y。二者不是朋友,且不敵對。輸出"Ok".變量含義: v:v[i]即容器i存放編號為i的人的所有敵人 f:f[i]表示編號i的人所在的集合編號。方法含義: initSet:初始化集合和容器 findSet:尋找元素所屬集合 unionSet:集合合并 *********************************************************************************************/ #include <iostream> #include <stdio.h> #include <string.h> #include <vector>using namespace std;const int maxn = 105; vector<int>v[maxn]; //存放某個人的敵人 int f[maxn]; //進行并查集操作。 void initSet(int N) {for(int i = 1; i <= N; i++) {f[i] = i;v[i].clear();} } int findSet(int x) {int temp = x;while(f[x] != x) {x = f[x];}//路徑壓縮。while(f[temp] != temp) {temp = f[temp];f[temp] = x;}return x; } void unionSet(int x,int y) {if(x != y) {f[x] = y;} } int main() {int N,M,K;int x,y,relation,fx,fy;while(~scanf("%d%d%d",&N,&M,&K)) {initSet(N);while(M--) {scanf("%d%d%d",&x,&y,&relation);if(relation == 1) {fx = findSet(x);fy = findSet(y);unionSet(fx,fy);}else {v[x].push_back(y);v[y].push_back(x);}}while(K--) {scanf("%d%d",&x,&y);fx = findSet(x);fy = findSet(y);bool flag = true; //兩個人不是敵人for(int i = 0; i < (int)v[x].size(); i++) {if(v[x][i] == y) {flag = false; //兩個人是敵人break;}}//兩個人是朋友。if(fx == fy) {if(flag) {printf("No problem\n");}else {printf("OK but...\n");}}else {if(flag) {printf("OK\n");}else {printf("No way\n");}}}}return 0; }L2-011 玩轉(zhuǎn)二叉樹
/************************************************************************************* Date: 2018/3/10 13:52 Author: Wen Yaxin解題思路:利用先序序列和中序序列確定二叉樹。 先序:根左右 中序:左根右 從中可知,給出先序序列,第一個元素就是根節(jié)點的值,則利用這個值,在中序 序列中查找,假設(shè)查找到第num個元素為根,則中序,num左側(cè)序列為左子樹的中序, num右側(cè)序列為右子樹的中序。劃分出左右子樹的先序和中序后再次求解。 求其鏡面樹:對于一個非空根節(jié)點,采用兩個整數(shù)交換的思想,對其進行左右根 節(jié)點的交換。 層次序列:對二叉樹進行廣度優(yōu)先遍歷即可。變量含義: preOrder:存放題目給出的先序序列 inOrder:存放題目給出的中序序列 levelOrder:存放最終層次遍歷的結(jié)果 cnt:數(shù)組下標方法含義: CreateTree:根據(jù)中序和先序構(gòu)建二叉樹 getSymmetryTree:獲取鏡像樹 getLevelOrder:獲取層次遍歷結(jié)果 *******************************************************************************************/ #include <iostream> #include <stdio.h> #include <string.h> #include <queue> #include <stdlib.h>using namespace std;int preOrder[50]; //存放先序序列 int inOrder[50]; //存放中序序列 int levelOrder[50],cnt; typedef struct Node {int data;struct Node *lchild;struct Node *rchild; }node; node* CreateTree(int *pre,int *in,int n) {node *b;int *p,k;if(n <= 0) return NULL; //節(jié)點個數(shù)小于等于0,是空樹。b = (node*)malloc(sizeof(node));b->data = *pre; //先序序列的第一個元素為根//已知根的值,在中序中確定序列。for(p = in; p < in+n; p++) {if(*p == *pre) {break;}}k = p-in;b->lchild = CreateTree(pre+1,in,k);b->rchild = CreateTree(pre+k+1,p+1,n-k-1);return b; } node* getSymmetryTree(node *root) {node *p; //輔助指針if(root != NULL) {p = root->lchild;root->lchild = root->rchild;root->rchild = p;getSymmetryTree(root->lchild);getSymmetryTree(root->rchild);}return root; } void getLevelOrder(Node *root) {queue<node*>qu;qu.push(root);Node *p;while(!qu.empty()) {p = qu.front();qu.pop();if(p != NULL) {levelOrder[cnt++] = p->data;if(p->lchild != NULL) {qu.push(p->lchild);}if(p->rchild != NULL) {qu.push(p->rchild);}}} } int main() {int n;while(~scanf("%d",&n)) {for(int i = 0; i < n; i++) {scanf("%d",&inOrder[i]);}for(int i = 0; i < n; i++) {scanf("%d",&preOrder[i]);}Node *root;root = CreateTree(preOrder,inOrder,n);getSymmetryTree(root);cnt = 0;getLevelOrder(root);for(int i = 0; i < n; i++) {printf("%d",levelOrder[i]);if(i != n-1) {printf(" ");}}printf("\n");}return 0; }L2-012 關(guān)于堆的判斷
/********************************************************************************** Date: 2018/3/12 9:41 Author: Wen Yaxin解題思路: 1.邊插入邊調(diào)整小頂堆。對于新插入的元素,如果比其根小,則 需要與其根調(diào)換位置,而這樣也會影響堆本身,因此可能需要多次 執(zhí)行該操作。使小值不斷上浮。 2.由于題目中給出的元素的值可能有重復(fù)的。所以不能采用直接去 查找元素的下標。而應(yīng)該枚舉根節(jié)點,根據(jù)根節(jié)點求左右節(jié)點。來 確定他們的關(guān)系。變量含義: n:n個元素 m:m次詢問 elem:存放n個元素的數(shù)組方法含義: Insert:插入第i個元素,并調(diào)整堆 createMinHeap:構(gòu)造小頂堆 judge1:判斷一個元素是否為根。 judge2:堆其余三種情況進行判斷。 ************************************************************************/ #include <iostream> #include <cstdio> #include <cstring>using namespace std;const int maxn = 1010; int n,m,elem[maxn]; void Insert(int i) {int temp = elem[i];while(i/2>0 && temp<elem[i/2]) {elem[i] = elem[i/2];i = i/2;}elem[i] = temp; } void createMinHeap() {for(int i = 2; i <= n; i++) {Insert(i);} } bool judge1(int num) {if(num == elem[1]) return true;else return false; } bool judge2(int num1,int num2,int type) {int lchild,rchild,i;//判斷兩個節(jié)點是否為兄弟節(jié)點。if(type == 1) {for(i = 1; i <= n/2; i++) {lchild = 2*i;rchild = 2*i + 1;if(rchild <= n) {if(elem[lchild]==num1 && elem[rchild]==num2) return true;if(elem[lchild]==num2 && elem[rchild]==num1) return true;}}return false;}//判斷num1是否為num2的父母if(type == 2) {for(i = 1; i <= n/2; i++) {lchild = 2*i;rchild = 2*i + 1;if(elem[i] == num1) {if(elem[lchild]==num2) return true;if(rchild<=n && elem[rchild]==num2) return true;}}return false;}//判斷num1是否是num2的孩子。for(i = 1; i <= n/2; i++) {lchild = 2*i;rchild = 2*i+1;if(elem[i] == num2) {if(elem[lchild]==num1) return true;if(rchild<=n && elem[rchild]==num1) return true;}}return false; } int main() {int num1,num2;char str[20];while(~scanf("%d%d",&n,&m)) {for(int i = 1; i <= n; i++) {scanf("%d",&elem[i]);}createMinHeap();getchar();bool flag;while(m--) {scanf("%d %s",&num1,str);//判斷是否為兄弟的情況if(str[0]=='a') {scanf("%d%s%s",&num2,str,str);flag = judge2(num1,num2,1);}else {//判斷num1是否為num2的孩子之一。scanf("%s",str);if(str[0] == 'a') {scanf("%s%s%d",str,str,&num2);flag = judge2(num1,num2,3);}else {scanf("%s",str);//判斷num1是否為根if(str[0] == 'r') {flag = judge1(num1);}//判斷num1是否為num2的父母else {scanf("%s%d",str,&num2);flag = judge2(num1,num2,2);}}}if(flag) {printf("T\n");}else {printf("F\n");}}}return 0; }L2-013 紅色警報
/********************************************************************************** Date: 2018/3/12 17:32 Author: Wen Yaxin解題思路:使用并查集,統(tǒng)計連通塊的個數(shù)。占領(lǐng)一個點后, 要去除所有與其相連的邊,則占領(lǐng)該點后,該點必孤立。該 點自己為一個集合,如果該點原來就孤立,則占領(lǐng)該點后連 通塊數(shù)不變,否則如果連通塊數(shù)只多了1,代表它自己貢獻了 那個1,其他情況,說明連通狀況改變了。變量含義: N:城市個數(shù),城市編號0~N-1 M:M條邊,沒有自環(huán),但是可能有重邊。 K:占領(lǐng)K個點 edge:用來存邊 head:相當于鏈式存儲圖的鏈表頭節(jié)點 vis:vis用來標記u-v這條無向邊,該標記用來去除重邊 edgeNum:邊的數(shù)量,不帶重邊。 f:集合 isDel:標記某條邊是否被刪除。方法含義: init:初始化一些變量 initSet:初始化各個集合 findSet:尋找元素所在的集合 unionSet:合并集合 addEdge:加邊函數(shù) getSetNum:統(tǒng)計集合個數(shù),即連通塊的個數(shù) delEdge:刪除與x相連的邊 **************************************************************************************/ #include <iostream> #include <cstdio> #include <cstring>using namespace std;const int maxn = 505; const int maxm = 5005; int N,M,K; struct Edge{int u,v,nex; }edge[maxm*2]; int head[maxn],vis[maxn][maxn],edgeNum,f[maxn]; int isDel[maxm*2]; void init() {memset(head,-1,sizeof(head));memset(vis,0,sizeof(vis));memset(isDel,0,sizeof(isDel));edgeNum = 0; } void initSet() {for(int i = 0; i < N; i++) {f[i] = i;} } int findSet(int x) {while(x != f[x]) {x = f[x];}return x; } void unionSet(int x,int y) {if(x != y) {f[x] = y;} } void addEdge(int x,int y) {edge[edgeNum].u = x;edge[edgeNum].v = y;edge[edgeNum].nex = head[x];head[x] = edgeNum++;edge[edgeNum].u = y;edge[edgeNum].v = x;edge[edgeNum].nex = head[y];head[y] = edgeNum++; } int getSetNum() {int num = 0;for(int i = 0; i < N; i++) {if(f[i]==i) {num++;}}return num; } void delEdge(int x) {for(int i = head[x]; i != -1; i=edge[i].nex) {if(isDel[i]==0) {isDel[i] = isDel[i^1] = 1; //一條邊和其反向邊是相鄰的。}} } int main() {int u,v,setNum,x,fu,fv;while(~scanf("%d%d",&N,&M)) {init();initSet();while(M--) {scanf("%d%d",&u,&v);if(!vis[u][v]) {addEdge(u,v);vis[u][v] = vis[v][u] = 1;fu = findSet(u);fv = findSet(v);unionSet(fu,fv);}}setNum = getSetNum();scanf("%d",&K);for(int i = 1; i <= K; i++) {scanf("%d",&x);delEdge(x);initSet();for(int j = 0; j < edgeNum; j++) {if(isDel[j]==0) {fu = findSet(edge[j].u);fv = findSet(edge[j].v);unionSet(fu,fv);}}if(getSetNum()==setNum || setNum+1==getSetNum()) {printf("City %d is lost.\n",x);}else {printf("Red Alert: City %d is lost!\n",x);}setNum = getSetNum();}if(K == N) {printf("Game Over.\n");}}return 0; }L2-014 列車調(diào)度
/********************************************************************************* Date: 2018/3/12 19:50 Author: Wen Yaxin解題思路:LIS 求解,LIS ->longest increasing sequence 8 4 2 5 3 9 1 6 7四個軌道: 1 2 4 83 56 97 8比9小,所以8先在道上等待。當前狀況如下: 軌道1 :8 -------------------------------------------- 然后4,4比8小,則4比8后到,和8停同一個軌道等待,當前狀況如下。 軌道1 :4 8 ------------------------------------------- 然后2,2比4小,2比4后到,和4停同一個軌道等待,當前狀況如下。 軌道1:2 4 8 ---------------------------------------------- 然后5,5比2大,則5比2先到,則需要令起軌道。當前狀況如下。 軌道1:2 4 8 軌道2:5 ---------------------------------------------- 然后3,3比2大,則3比2先到,3比5小,3比5后到,則3在5后等待,當前狀況如下。 軌道1:2 4 8 軌道2:3 5 ----------------------------------------------------------------- 然后9,9比2大,9比3大,因此9需要令起軌道。當前狀況如下。 軌道1:2 4 8 軌道2:3 5 軌道3:9 --------------------------------------------------------- 然后1,1比2小,則1比2后到,可以排在2后面,當前狀況如下。 軌道1:1 2 4 8 軌道2:3 5 軌道3:9 -------------------------------------------------- 然后6,6比1和3都大,則6比1和3先到,6無法排在1,3后,但6比9小,當前狀況如下 軌道1:1 2 4 8 軌道2:3 5 軌道3:6 9 --------------------------------------------- 然后7,7比1,3,6,都大,無法排在他們后,則令起軌道,當前狀況如下。 軌道1:1 2 4 8 軌道2:3 5 軌道3:6 9 軌道4:7 ----------------------------------------------------------- 從推導(dǎo)過程可以看出,對于當前要進入軌道的列車,如果以存在的軌道上排列的 最小編號的火車的值比當前值大,則他們位于同一軌道,否則當前列車必須令 起軌道。這個問題就是LIS,LIS有一個logN的算法,其思想和推導(dǎo)過程如出一轍, 如果當前值比LIS的最后一個值大,則這個元素就是LIS新的末尾,否則二分查找 LIS中第一個大于該元素的數(shù),并替換這個數(shù)。最后LIS的長度就是答案。變量含義: LIS:輔助求取最長遞增子序列的長度,但數(shù)組內(nèi)部可能并非是最長遞增子序列對應(yīng)的值。 x:用來接收題目給出的一個個元素方法含義: binarySearch:用來查找LIS中第一個大于value的值的位置。 ******************************************************************************************/ #include <iostream> #include <cstdio> #include <cstring>using namespace std;const int maxn = 1e5+10; int lis[maxn],x; //求最長上升子序列。 int binarySearch(int len,int value) {int low,high,mid;low = 1;high = len;while(low < high) {mid = (low+high)/2;if(lis[mid]>=value) {high = mid;}else {low = mid+1;}}return low; } int main() {int n,x;while(~scanf("%d",&n)) {int len = 1;scanf("%d",&lis[1]);for(int i = 1; i < n; i++) {scanf("%d",&x);if(x > lis[len]) {len++;lis[len] = x;}else {//查找數(shù)組中第一個比x大的整數(shù)。int pos = binarySearch(len,x);lis[pos] = x;}}printf("%d\n",len);}return 0; }L2-015 互評成績
/**************************************************************** Date: 2018/3/12 20:29 Author: Wen Yaxin解題思路:水題,按照題目描述求解即可。變量含義: score:存放n個人的成績。 ************************************************************/ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm>using namespace std;const int maxn = 1e4+10; double score[maxn]; int main() {int n,k,m;double Min,Max,sum,s;while(~scanf("%d%d%d",&n,&k,&m)) {for(int i = 0; i < n; i++) {scanf("%lf",&Min);sum = Max = Min;for(int j = 1; j < k; j++) {scanf("%lf",&s);sum += s;Max = max(Max,s);Min = min(Min,s);}score[i] = (sum-Max-Min)/(k-2);}sort(score,score+n);for(int i = n-m; i < n; i++) {printf("%.3lf",score[i]);if(i != n-1) {printf(" ");}}printf("\n");}return 0; }L2-016 愿天下有情人都是失散多年的兄妹
/********************************************************************************* Date 2018/3/16 18:03 Author Wen Yaxin解題思路: 首先一個人,五代之內(nèi)的家屬最多 1+2+4+8+16 = 31. 因此可以先將人物關(guān)系存儲起來,如果a是b的父母,則建一條由b指向 a的邊。采用暴力的思想,對于一個編號存在的人,把它無代以內(nèi)的家 屬包括它自己存在它對應(yīng)的容器中。注意:不要只顧存直接給出性別的人的性別,也要存父母的性別,這是 題目中暗示的,忘記存儲的話只能過兩組數(shù)據(jù)。變量含義: cnt:作為edge的下標,每存一條邊,右移一位。 sex:sex[i]存放性別,sex[i]為0,代表編號為i的人不存在,sex[i]=1代表男,sex[i]=2代表女 head:頭節(jié)點。 V:v[i]是一個vector,用來存放編號為i的人五代以內(nèi)的所有家屬 edge:存放給出的關(guān)系 node:節(jié)點,成員變量有,代數(shù)和人員編號方法含義: addEdge:加邊函數(shù) bfs:bfs(i),求編號為i的人五代以內(nèi)的所有親屬,并存入其編號對應(yīng)的vector *****************************************************************************************/ #include <iostream> #include <stdio.h> #include <string.h> #include <vector> #include <queue>using namespace std;const int maxn = 1e5+10; int cnt,sex[maxn],head[maxn]; vector<int>v[maxn]; struct Edge{int v;int nex; }edge[maxn*10]; void addEdge(int u,int v) {edge[cnt].v = v;edge[cnt].nex = head[u];head[u] = cnt++; } typedef struct Node {int u;int level; }node; void bfs(int x) {queue<node>qu;node cur,nex;cur.u = x;cur.level = 1;qu.push(cur);int temp;while(!qu.empty()) {cur = qu.front();qu.pop();if(cur.level > 5) {continue;}temp = cur.u;v[x].push_back(temp);for(int i = head[temp]; i != -1; i = edge[i].nex) {nex.u = edge[i].v;nex.level = cur.level + 1;qu.push(nex);}} } int main() {int n,me,fa,mo,m;char ch;while(~scanf("%d",&n)) {for(int i = 0; i < maxn; i++) {v[i].clear();}cnt = 0;memset(head,-1,sizeof(head));memset(sex,0,sizeof(sex));for(int i = 0; i < n; i++) {scanf("%d %c%d%d",&me,&ch,&fa,&mo);if(ch == 'M') {sex[me] = 1; //是男性。}else {sex[me] = 2;}if(fa != -1) {addEdge(me,fa);sex[fa] = 1; //不要忘存父母的性別}if(mo != -1) {addEdge(me,mo);sex[mo] = 2; //不要忘存父母的性別}}for(int i = 0; i < maxn; i++) {//該編號存在if(sex[i] != 0) {bfs(i);}}scanf("%d",&m);int x,y;while(m--) {scanf("%d%d",&x,&y);//同性不可通婚。if(sex[x] == sex[y]) {printf("Never Mind\n");}else {//判斷無代內(nèi)是否有共同親人。bool ok = true;for(int i = 0; i < (int)v[x].size(); i++) {for(int j = 0; j < (int)v[y].size(); j++) {if(v[x][i] == v[y][j]) {ok = false;break;}}if(!ok) break;}if(ok) {printf("Yes\n");}else {printf("No\n");}}}}return 0; }L2-017 人以群分
/******************************************************* Date 2018/3/13 19:21 Author Wen Yaxin解題思路:對數(shù)組排序,然后盡可能平分。變量含義: active:存放每個人的活躍度 *******************************************************/ #include <iostream> #include <stdio.h> #include <algorithm> #include <cstdio>using namespace std;const int maxn = 1e5+10; int active[maxn]; int main() {int n,tmp1,tmp2;while(~scanf("%d",&n)) {for(int i = 0; i < n; i++) {scanf("%d",&active[i]);}sort(active,active+n);tmp1 = n/2;tmp2 = n-tmp1;printf("Outgoing #: %d\n",max(tmp1,tmp2));printf("Introverted #: %d\n",min(tmp1,tmp2));int limit = tmp1;tmp1 = tmp2 = 0;for(int i = 0; i < limit; i++) {tmp1 += active[i];}for(int i = limit; i < n; i++) {tmp2 += active[i];}printf("Diff = %d\n",abs(tmp2-tmp1));}return 0; }L2-018 多項式A除以B
L2-019 悄悄關(guān)注
/*********************************************************************************** Date 2018/3/13 20:30 Author Wen Yaxin解題思路:對于判斷姓名存不在可以通過map映射,或者對關(guān)注的人 排序,然后再對m個人進行二分查找。變量含義: arr1:存放關(guān)注列表中的人。 arr2:存放輸入的m個名字 num:存放輸入的m個人對應(yīng)的點贊數(shù)量 ans:存放答案方法含義: binarySearch:二分查找某個名字是否存在。 **********************************************************************************/ #include <iostream> #include <stdio.h> #include <algorithm> #include <cstdio>using namespace std;const int maxn = 10010; string arr1[maxn],arr2[maxn],ans[maxn]; double num[maxn]; int binarySearch(string s,int len) {int low,high,mid;low = 0;high = len;while(low <= high) {mid = (low+high)/2;if(arr1[mid] == s) {return mid;}else if(s < arr1[mid]) {high = mid-1;}else {low = mid+1;}}return -1; } int main() {int n,m,cnt;while(~scanf("%d",&n)) {for(int i = 0; i < n; i++) {cin>>arr1[i];}sort(arr1,arr1+n); //按照名字從小到大排序double aver,sum = 0;cin>>m;for(int i = 0; i < m; i++) {cin>>arr2[i]>>num[i];sum += num[i];}aver = sum/m;cnt = 0;for(int i = 0; i < m; i++) {if(num[i]>aver) {if(binarySearch(arr2[i],n-1) == -1) {ans[cnt++] = arr2[i];}}}if(cnt == 0) {cout<<"Bing Mei You"<<endl;}else {sort(ans,ans+cnt);for(int i = 0; i < cnt; i++) {cout<<ans[i]<<endl;}}}return 0; }L2-020 功夫傳人
/******************************************************************** Date 2018/3/15 20:26 Author Wen Yaxin解題思路: 去年天梯賽打了170分,做了這個題目,當時感覺給出的輩分順序 不會嚴格按照輩分來,但是自己就是按這種想法寫的,而且提交過了,當時以為是僥幸, 今年又寫了一次,才發(fā)現(xiàn)題目中說了嚴格按照輩分給出,才發(fā)現(xiàn)本身 就是嚴格按輩分給的數(shù)據(jù),所以題目就會便得很簡單。 按照題目描述做就好,只要輸入的關(guān)系普嚴格按照輩分,這個題目就是水題。變量含義: p:存放每個人的信息,其師傅編號,是否得道者,其功力值。 ****************************************************************/ #include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<cmath> #define INF 999999using namespace std;struct people{int parent; //父母double power; //功力int flag; //是否是得道者 }p[100005]; int main(){//N整個師門總?cè)藬?shù),Z祖師爺?shù)墓αχ?#xff0c;R功夫折扣百分比,int N,K,fa,t;double Z,R;while(~scanf("%d%lf%lf",&N,&Z,&R)){p[0].power = Z; //0用來存放祖師爺for(int i = 0; i < N; i++){scanf("%d",&K);//K = 0代表該人是得道者if(K == 0) {//flag為1代表是得道者p[i].flag = 1; //輸入功力被放大的倍數(shù)scanf("%d",&t); //祖師爺是得道者if(i == 0){p[0].power = p[0].power*t;}else{ //其他人是得到者,對其師傅功力打折扣后再放大相應(yīng)倍數(shù)。fa = p[i].parent;p[i].power = p[fa].power*(100-R)/100*t;}}else{for(int j = 0; j < K; j++){scanf("%d",&t);p[t].parent = i;p[t].flag = 0; //不是得道者。p[t].power = p[i].power*(100-R)/100;}}}double ans = 0;for(int i = 0; i < N; i++){if(p[i].flag == 1){ans = ans + p[i].power;}}printf("%d\n",(int)ans);}return 0; }L2-021 點贊狂魔
L2-022 鏈表重排
/*********************************************************************** Date 2018/3/16 14:41 Author Wen Yaxin解題思路: 按照鏈表的順序,順序把節(jié)點存儲下來,然后分別定義兩個指針 指向首尾,讓兩個指針不斷向中間靠攏。坑點:輸入的節(jié)點不一定都在鏈表里面。這點超級坑,錯了好多次。 例如: 1 4 1 1 2 1 2 3 3 3 -1 4 4 -11->2->3 是一條鏈表,但是4 4 -1,只是一個無用的節(jié)點。 如果不考慮,則會過不去測試點3,里面的數(shù)據(jù)一個都過不去。變量含義: node:存放題目輸入的數(shù)據(jù) arr:順序存儲鏈表節(jié)點的信息 ans:存儲答案。 ***************************************************************************/ #include <iostream> #include <stdio.h>using namespace std; const int maxn = 1e6+10; struct Node {int data;int nex; }node[maxn]; struct Elem {int add;int data;int nex; }arr[maxn],ans[maxn]; int main() {int head,n;int x,y,z,i,j,k;while(~scanf("%d%d",&head,&n)) {for(i = 0; i < n; i++) {scanf("%d%d%d",&x,&y,&z);node[x].data = y;node[x].nex = z;}int cnt = 0;while(head != -1) {arr[cnt].add = head;arr[cnt++].data = node[head].data;head = node[head].nex;}i = 0;j = cnt-1;//這里是cnt-1,而不是n-1,可能有元素不再鏈表中。k = 0;while(i <= j) {if(i == j) {ans[k].add = arr[i].add;ans[k].data = arr[i].data;ans[k++].nex = -1;break;}ans[k].add = arr[j].add;ans[k].data = arr[j].data;ans[k++].nex = arr[i].add;j--;ans[k].add = arr[i].add;ans[k].data = arr[i].data;ans[k++].nex = arr[j].add;i++;}//printf("%d %d\n",i,j);ans[cnt-1].nex = -1;for(i = 0; i < cnt-1; i++) {printf("%05d %d %05d\n",ans[i].add,ans[i].data,ans[i].nex);}printf("%05d %d -1\n",ans[cnt-1].add,ans[cnt-1].data);}return 0; }L2-023 著色圖問題
L2-024 部落
/****************************************************************************** Date 2018/3/16 17:07 Author Wen Yaxin解題思路: 用數(shù)組標記人的編號,然后用并查集對集合進行合并,但是需要確定 集合合并的方向。即前一個人要合并到后一個人上,或反過來,但是 一定要有一個合并的準則。注意:查詢元素所屬集合過程要進行路徑壓縮,否則有一組數(shù)據(jù)將會 運行超時。所謂路徑壓縮很簡單,即找到元素所屬集合后,把路徑中 的所有元素的所屬集合直接指向所屬集合的編號,而不是指向其前驅(qū)。變量含義: f:f[i]存放i所屬的集合。 vis:vis[i]標記編號為i的人是否存在。方法含義: initSet:集合初始化 findSet:查找元素所在集合 unionSet:集合合并 ******************************************************************************/ #include <iostream> #include <stdio.h> #include <string.h>using namespace std;const int maxn = 1e4+3; int f[maxn],vis[maxn]; void initSet() {for(int i = 0; i < maxn; i++) {f[i] = i;} } int findSet(int x) {int temp = x;while(x != f[x]) {x = f[x];}//路徑壓縮。不壓縮的話,有一組數(shù)據(jù)超時while(temp != f[temp]) {temp = f[temp];f[temp] = x;}return x; } void unionSet(int x,int y) {f[x] = y; } int main() {int n,k,c,cnt,num,fu,fv;while(~scanf("%d",&n)) {memset(vis,0,sizeof(vis));cnt = num = 0;initSet();while(n--) {scanf("%d",&k);if(k) {scanf("%d",&c);if(!vis[c]) {vis[c] = 1;cnt++;}fu = findSet(c);for(int j = 1; j < k; j++) {scanf("%d",&c);if(!vis[c]) {vis[c] = 1;cnt++;}fv = findSet(c);if(fu != fv) {unionSet(fu,fv);}fu = findSet(c);}}}for(int i = 1; i < maxn; i++) {if(vis[i]==1 && findSet(i)==i) {num++;}}printf("%d %d\n",cnt,num);scanf("%d",&c);int u,v;while(c--) {scanf("%d%d",&u,&v);fu = findSet(u);fv = findSet(v);if(fu == fv) {puts("Y");}else {puts("N");}}}return 0; }總結(jié)
以上是生活随笔為你收集整理的PAT天梯赛Level2题目题解汇总的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python手机触屏代码_JS移动客户端
- 下一篇: 蚂蚁金服面试经验分享