算法搞定[机试]算法刷题 全文超过80页pdf
Posted duye
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法搞定[机试]算法刷题 全文超过80页pdf相关的知识,希望对你有一定的参考价值。
目录
算法专题
一、树和图
1. 二叉树构造和遍历
给出二叉树的后序(postorder)遍历和中序(inorder)遍历,建立二叉树,并得到树的层次遍历(level traversal)。
- preorder:根 - 左子树 - 右子树
- inorder:左子树 - 根 - 右子树 (即为深度优先)
- postorder:左子树 - 右子树 - 根
- level traversal:层次遍历,即广度优先
#include<bits/stdc++.h>
using namespace std;
//由树的中序和后序=>层析遍历
typedef struct BiTree{
int num;
BiTree *left;
BiTree *right;
}BT;
int post[10010];
int in[10010];
BT *T;
//建立二叉树
BT* CreateBiTree(int postl,int postr,int inl,int inr){
//创建二叉树
//递归边界,重要!
if(postl > postr){
return NULL;
}
//printf("--------------------
");
//寻找根节点
int rooti;
for(int i = inl;i<=inr;i++){
if(in[i] == post[postr]){
rooti = i;
break;
}
}
BT *node = (BT*)malloc(sizeof(BiTree));
node->num = in[rooti];
node->left = CreateBiTree(postl,postl+(rooti-inl)-1,inl,rooti-1);
node->right = CreateBiTree(postl+(rooti-inl),postr-1,rooti+1,inr);
return node;
}
//层析遍历,借助queue
void bfs(BT* root) {
queue<BT*> q;
q.push(root);
while(!q.empty()){
BT *temp = q.front();
q.pop();
printf("%d ",temp->num);
if(temp->left) q.push(temp->left);
if(temp->right) q.push(temp->right);
}
}
int main(){
int n;
cin>>n;
//输入后序
for(int i = 0;i<n;i++){
cin>>post[i];
}
//输入中序
for(int i = 0;i<n;i++){
cin>>in[i];
}
T = CreateBiTree(0,n-1,0,n-1);
bfs(T);
return 0;
}
2. 朋友圈 - 并查集
#include<bits/stdc++.h>
using namespace std;
int parent[10010];
void init(int n){
for(int i = 0;i<=n;i++)
parent[i] = -1;
}
//寻找祖先+路径压缩
int find(int x){
int s;
for(s = x;parent[s] > 0; s = parent[s]);
while(s!=x){
int tmp = parent[x];
parent[x] = s;
x = tmp;
}
return s;
}
void Union(int a,int b){
int fa = find(a),fb = find(b);
int tmp = parent[fa] + parent[fb];
if(parent[fa] > parent[fb]){
parent[fa] = fb;
parent[fb] = tmp;
}else{
parent[fa] = tmp;
parent[fb] = fa;
}
}
int main(){
int n,m;
cin>>n>>m;
int na,a[10010];
init(n);
for(int i = 0;i<m;i++){
cin>>na;
for(int j = 0;j<na;j++){
cin>>a[j];
}
for(int j = 1;j<na;j++){
if(find(a[j])!=find(a[j-1])){
Union(a[j],a[j-1]);
}
}
}
int mins = 100100;
for(int i =1;i<=n;i++){
if(parent[i]<0){
if(parent[i] < mins){
mins = parent[i];
}
}
}
cout<<-mins<<endl;
}
3. 公共朋友 - 非朋友圈
poj4109 |
---|
描述:小明和小红去参加party。会场中总共有n个人,这些人中有的是朋友关系,有的则相互不认识。朋友关系是相互的,即如果A是B的朋友,那么B也是A的朋友。小明和小红想知道其中某两个人有多少个公共的朋友。 |
输入:第一行为一个正整数c,代表测试数据的个数。接下来是c组测试数据。 对于每组测试数据,第一行是三个数字n(2<=n<=100),m和k,分别表示会场中的人数,已知的朋友关系数目,问题的数目。接下来的m行,每行用两个数字i和j(1<=i,j<=n)表示了一个朋友关系,表示第i个人和第j个人是朋友关系。接下来的k行,每行用两个数字i和j(1<=i,j<=n)表示一个问题,请问第i个人和第j个人有多少公共的朋友。 |
输出: 对于第i组测试数据,首先输出一行”Case i:”,接下来得k行代表了k个问题,每行输出第i个人和第j个人有多少公共的朋友。 |
利用set去重:
#include<bits/stdc++.h>
using namespace std;
vector<int> g[104];
int main(){
int Case;
cin>>Case;
for(int cases = 1;cases<=Case;cases++){
for(int i = 0;i<100;i++){
g[i].clear();
}
int n,m,k;
cin>>n>>m>>k;
int a,b;
for(int i = 0;i<m;i++){
cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
cout<<"Case "<<cases<<":"<<endl;
for(int i = 0;i<k;i++){
cin>>a>>b;
set<int> s;
int n1 = g[a].size();
int n2 = g[b].size();
for(int i = 0;i<n1;i++){
s.insert(g[a][i]);
}
for(int i = 0;i<n2;i++){
s.insert(g[b][i]);
}
int n3 = s.size();
cout<<n1+n2-n3<<endl;
}
}
return 0;
}
4. 哈夫曼树
哈夫曼树的定义
定义:哈夫曼树即为最小二叉树。所谓最优指的是树的带权路径长度最小,即:二叉树的树枝赋权值,从根节点到所有叶子节点的路径上权值之和最小,这样的树为哈夫曼树。相应的应用是哈夫曼编码。
构造哈夫曼树 - 优先队列实现
题目: CSU - 1588 |
---|
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。? 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。? 因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。? 例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。 |
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//优先队列实现哈夫曼树
int n;
priority_queue<ll,vector<ll>,greater<ll> > que;
int main(){
cin>>n;
int x;
for(int i = 0;i<n;i++){
cin>>x;
que.push(x);
}
int ans = 0;
while(que.size()>1){
ll a1 = que.top();
que.pop();
ll a2 = que.top();
que.pop();
ans+=a1+a2;
que.push(a1+a2);
}
cout<<ans<<endl;
return 0;
}
5. 其他二叉树性质相关计算
poj 2788 (√)
poj 2756 (√)
6. 图的连通分量
寻找一个图中满足条件的所有连通分量
九度1446:Head of a Gang |
---|
描述:One way that the police finds the head of a gang is to check people‘s phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A "Gang" is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threthold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads. |
输入:第一行两个整数,电话数n和阈值k。接下来n行,(A B c),每行一个电话,表示A打给B,且通话时间为c。注意,名字A和B是由三个大写字母组成的。 |
输出:第一行表示团伙数n,接下来n行每行为一个团伙,输出为该团伙的头目名字和团伙成员数。 |
样例:
输入:
8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
输出:
2
AAA 3
GGG 3
题目分析
- 找图中所有的连通子图。注意题目描述不清楚,实际上,只要连通就算一个团伙,而不是一定要子图为完全图。
- 用并查集,可以找到所有连通块。
- 判断连通块的通话时间总数是否满足阈值,需要找到该连通块所有的节点编号,故同时使用邻接矩阵存储,用dfs找到所有节点并保存。
- 找头目。找连接图中权值最大的点,故同时用数组a[MAX]记录每个点的权值之和,在输入时就记录。
- 用优先队列(pair)存储所有找到的头目结点编号以及该团伙人数,最后按序输出即可。
- 注意输入的名字是三个大写字母,故将其hash成整数,最后输出再转回字符数组。
解决
#include<bits/stdc++.h>
using namespace std;
int parent[18005];
int node[18005];
int n,k;
vector<int > g[18000];
vector<int> que;
int vis[18000];
typedef pair<int,int > P;
priority_queue<P,vector<P>,greater<P> > res;
void init(){
for(int i = 0;i<18000;i++){
parent[i]=-1;
node[i] = 0;
}
}
int hashName(const char name[]){
return (name[0]-'A')*26*26 + (name[1] - 'A') *26 +(name[2] -'A');
}
void intToName(int x,char name[4]){
char a = x%26+'A';
char b = x%(26*26)/26 +'A';
char c = x/26/26 + 'A';
name[0] = a;name[1] = b;name[2] = c;name[3]='