01 | #include <iostream> |
02 | using namespace std; |
03 | int h[16],n; |
04 |
05 | void swap( int x, int y) |
06 |
07 | { |
08 | int t=h[x]; |
09 | h[x]=h[y]; |
10 | h[y]=t; |
11 | } |
12 | //建立堆需要向下调整 |
13 | //建立向下调整函数。 |
14 | void siftdown( int i) //传入i从每一个小的堆(堆顶)向下调整。 |
15 | { |
16 | int t,flag=0; //flag用来标记是否需要继续向下调整 |
17 |
18 | //当i结点有儿子(至少有左儿子)并且有需要继续调整的时候循环就执行。 |
19 |
20 |
21 | while (i*2<=n&&flag==0) |
22 | { |
23 | if (h[i]>h[i*2]) //首先判断他跟做儿子的关系 |
24 | t=i*2; //如果小于左儿子那就用t来记录较大值的位置,并没有进行交换, |
25 | else |
26 | t=i; |
27 | //判断完了左儿子在于右儿子比较。 |
28 | //首先得判断是否有右儿子。 |
29 | if (i*2+1<=n) |
30 | { |
31 | if (h[t]>h[i*2+1]) |
32 | t=i*2+1; |
33 | } |
34 | if (t!=i) //如果最后发现t不是i自己了那就进行交换。 |
35 | swap(t,i); |
36 | else |
37 | flag=1; |
38 | i=t; //无论是否交换,最后更新一下i的值。 |
39 | } |
40 | } |
41 | void creat() |
42 | { |
43 | int i; |
44 | //从最后一个非叶节点到第一个结点依次进行向下调整。 |
45 | for (i=n/2; i>=1; i--) |
46 | { |
47 | siftdown(i); |
48 | } |
49 | } |
50 | void heapsort() |
51 | { |
52 | while (n>1) |
53 | { |
54 | swap(1,n); |
55 | n--; |
56 | siftdown(1); |
57 | } |
58 | } |
59 | int main() |
60 | { |
61 | int x,i,num,t; |
62 | cin>>num>>x; |
63 | for ( i=1; i<=x; i++) |
64 | cin>>h[i]; |
65 | n=x; |
66 | creat(); |
67 | for (i=x+1;i<=num;i++) |
68 | { |
69 | cin>>t; |
70 | if (t>h[1]) |
71 | { |
72 | h[1]=t; |
73 | creat(); |
74 | } |
75 | } |
76 | heapsort(); |
77 | for (i=1;i<x;i++) |
78 | cout<<h[i]<< " " ; |
79 | cout<<h[x]<<endl; |
80 | return 0; |
81 | } |
82 |
example :有四个叶子结点a,b,c,d,权值分别为7,5,2,4构造有4个结点的二叉树。构造有4个叶子节点的二叉树。WPL取权值最小的两个构造成一个新的树,重复此操作,最终构成一个哈弗曼树。
1、路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或子孙结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL;
树-堆结构练习——合并果子之哈夫曼树
#include<bits/stdc++.h>Time Limit: 1000MS Memory Limit: 65536KBProblem Description
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所消耗体力之和。因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。Input
第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个ai(1<=ai<=20000)是第i个果子的数目。Output
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。Example Input
3 1 2 9Example Output
15链表代码:
001
#include<bits/stdc++.h>
002
using
namespace
std;
003
int
f;
004
struct
node
005
{
006
int
data;
007
struct
node *next;
008
};
009
int
main()
010
{
011
int
n,z,i,sum=0;
012
struct
node *p,*head,*q1,*q2,*p1,*p2;
013
head=
new
node;
014
head->next=NULL;
015
cin>>n;
016
if
(n==1)
017
{
018
cin>>z;
019
cout<<z<<endl;
020
}
021
else
022
{
023
p=
new
node;
024
cin>>p->data;
025
p->next=NULL;
//建一个结点。
026
//每当有新的数输入就建造一个新的结点,
027
//头结点为空用来链接这个链表(主要是用来链接第一个结点)
028
head->next=p;
//(进行链表的链接。)
029
for
(i=2;i<=n;i++)
030
{
031
p=
new
node;
032
cin>>p->data;
033
q1=head;
//这一步是准备遍历链表按照顺序插入了;
034
q2=head->next;
//两个游动指针才能插入一个新的结点。
035
while
(q2)
036
{
037
if
(q2->data>p->data)
038
{
039
q1->next=p;
040
p->next=q2;
041
break
;
042
}
043
else
044
{
045
q1=q1->next;
046
q2=q2->next;
047
}
048
}
049
if
(q1->next==NULL)
050
q1->next=p;
//如果找到链表末尾都没有找到更大的值
051
//就直接把这个值放在表尾。
052
}
053
p1=head;
054
p2=head->next;
055
056
//再次使用两个游动指针。
057
058
while
(p2->next!=NULL)
059
{
060
p1=p1->next;
061
p2=p2->next;
062
//两个游动指针是用来遍历 ,
063
sum+=p1->data+p2->data;
//求和。
064
p=
new
node;
//求和之后重复新节点的建立
065
p->data=p1->data+p2->data;
//新节点的数据域等于上两个的和
066
p->next=NULL;
067
q1=p2;
068
q2=p2->next;
//使用两个游动指针把新建好的结点插入合适位置形成有序链表。
069
while
(q2)
070
{
071
if
(q2->data>p->data)
072
{
073
q1->next=p;
074
p->next=q2;
075
break
;
076
}
077
else
078
{
079
q1=q1->next;
080
q2=q2->next;
081
}
082
}
083
if
(q1->next==NULL)
084
q1->next=p;
//重复(没有找到比他大的就往最后面插入)
085
p1=p1->next;
086
p2=p2->next;
087
}
088
cout<<sum<<endl;
089
}
090
return
0;
091
}
using namespace std;
int a[10000];
int main()
{
int n,a1,a2,i;
int sum=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
}
priority_queue<int , vector<int> , greater<int> >q;//从小到大排列
for(i=0;i<n;i++)
{
q.push(a[i]);//进入队列
}
while(q.size()>1)//因为最后只剩下一组,所以控制长度大于1
{
a1=q.top();//将a1定义为首元素
q.pop();//出队列
a2=q.top();//将a2定义为首元素
q.pop();//出队列
sum+=a1+a2;
q.push(a1+a2);//这里注意将a1+a2进入队列,而不是sum
}
cout<<sum<<endl;//最后输出sum
return 0;
}
超时代码。
#include<bits/stdc++.h>
using namespace std;
int a[10005];
int cp(int a,int b)
{
return a>b;
}
int main()
{
int n,i;
int sum=0;
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
sort(a,a+n,cp);
for(i=0;n>1;i++)
{
sum=a[n-1]+a[n-2]+sum;
a[n-2]=a[n-1]+a[n-2];
n-=1;
sort(a,a+n,cp);
}
cout<<sum<<endl;
return 0;
}
字典树
Problem Description
遇到单词不认识怎么办? 查字典啊,已知字典中有n个单词,假设单词都是由小写字母组成。现有m个不认识的单词,询问这m个单词是否出现在字典中。
Input
含有多组测试用例。
第一行输入n,m (n>=0&&n<=100000&&m>=0&&m<=100000)分别是字典中存在的n个单词和要查询的m个单词.
紧跟着n行,代表字典中存在的单词。
然后m行,要查询的m个单词
n=0&&m=0 程序结束
数据保证所有的单词都是有小写字母组成,并且长度不超过10
Output
若存在则输出Yes,不存在输出No .
Example Input
3 2 aab aa ad ac ad 0 0
Example Output
No Yes
01
#include<bits/stdc++.h>
02
using
namespace
std;
03
int
f;
04
struct
node
05
{
06
char
data[28];
07
struct
node *l,*r;
08
};
09
struct
node*creat(
struct
node*root,
char
ch[])
//建立字典树唯一
10
//不同于有序二叉树之处就是字符串的链接
11
{
12
if
(root==NULL)
13
{
14
root=
new
(node);
15
root->l=root->r=NULL;
16
strcpy
(root->data,ch);
17
}
18
else
19
{
20
if
(
strcmp
(ch,root->data)<0)
21
root->l=creat(root->l,ch);
22
else
23
root->r=creat(root->r,ch);
24
}
25
return
root;
26
}
27
void
searchtree(
struct
node*root,
char
s[])
28
{
29
if
(root)
30
{
31
if
(
strcmp
(root->data,s)>0)
32
searchtree(root->l,s);
33
else
if
(
strcmp
(root->data,s)<0)
34
searchtree(root->r,s);
35
else
36
f=1;
37
}
38
}
39
int
main()
40
{
41
int
n,m;
42
char
a[12],s[12];
43
while
(cin>>n>>m)
44
{
45
if
(n==0&&m==0)
46
break
;
47
struct
node*t;
48
t=NULL;
49
while
(n--)
50
{
51
cin>>a;
52
t=creat(t,a);
53
}
54
while
(m--)
55
{
56
cin>>s;
57
f=0;
58
searchtree(t,s);
59
if
(f==1)
60
cout<<
"Yes"
<<endl;
61
else
62
cout<<
"No"
<<endl;
63
}
64
}
65
return
0;
66
}
Fence Repair
Time Limit: 2000MS Memory Limit: 65536KBProblem Description
Line 1: One integer NLine 1: One integer: the minimum amount of money he must spend to make NExample Input
3 8 5 8Example Output
34
01
#include<bits/stdc++.h>
02
using
namespace
std;
03
struct
node
04
{
05
long
long
data;
06
struct
node *next;
07
};
08
int
main()
09
{
10
long
long
n,z,i,sum=0;
11
struct
node *p,*head,*q1,*q2,*p1,*p2;
12
head=
new
node;
13
head->next=NULL;
14
cin>>n;
15
if
(n==1)
16
{
17
cin>>z;
18
cout<<z<<endl;
19
}
20
else
21
{
22
p=
new
node;
23
cin>>p->data;
24
p->next=NULL;
//建一个结点。
25
//每当有新的数输入就建造一个新的结点,
26
//头结点为空用来链接这个链表(主要是用来链接第一个结点)
27
head->next=p;
//(进行链表的链接。)
28
for
(i=2;i<=n;i++)
29
{
30
p=
new
node;
31
cin>>p->data;
32
q1=head;
//这一步是准备遍历链表按照顺序插入了;
33
q2=head->next;
//两个游动指针才能插入一个新的结点。
34
while
(q2)
35
{
36
if
(q2->data>p->data)
37
{
38
q1->next=p;
39
p->next=q2;
40
break
;
41
}
42
else
43
{
44
q1=q1->next;
45
q2=q2->next;
46
}
47
}
48
if
(q1->next==NULL)
49
q1->next=p;
//如果找到链表末尾都没有找到更大的值
50
//就直接把这个值放在表尾。
51
}
52
p1=head;
53
p2=head->next;
54
55
//再次使用两个游动指针。
56
57
while
(p2->next!=NULL)
58
{
59
p1=p1->next;
60
p2=p2->next;
61
//两个游动指针是用来遍历 ,
62
sum+=p1->data+p2->data;
//求和。
63
p=
new
node;
//求和之后重复新节点的建立
64
p->data=p1->data+p2->data;
//新节点的数据域等于上两个的和
65
p->next=NULL;
66
q1=p2;
67
q2=p2->next;
//使用两个游动指针把新建好的结点插入合适位置形成有序链表。
68
while
(q2)
69
{
70
if
(q2->data>p->data)
71
{
72
q1->next=p;
73
p->next=q2;
74
break
;
75
}
76
else
77
{
78
q1=q1->next;
79
q2=q2->next;
80
}
81
}
82
if
(q1->next==NULL)
83
q1->next=p;
//重复(没有找到比他大的就往最后面插入)
84
p1=p1->next;
85
p2=p2->next;
86
}
87
cout<<sum<<endl;
88
}
89
return
0;
90
}
数据结构实验之二叉树六:哈夫曼编码
Time Limit: 1000MS Memory Limit: 65536KBProblem Description
字符的编码方式有多种,除了大家熟悉的ASCII编码,哈夫曼编码(Huffman Coding)也是一种编码方式,它是可变字长编码。该方法完全依据字符出现概率来构造出平均长度最短的编码,称之为最优编码。哈夫曼编码常被用于数据文件压缩中,其压缩率通常在20%~90%之间。你的任务是对从键盘输入的一个字符串求出它的ASCII编码长度和哈夫曼编码长度的比值。
Input
输入数据有多组,每组数据一行,表示要编码的字符串。Output
对应字符的 ASCII 编码长度 la , huffman 编码长度 lh 和 la/lh 的值 ( 保留一位小数 ) ,数据之间以空格间隔。Example Input
AAAAABCD THE_CAT_IN_THE_HATExample Output
64 13 4.9 144 51 2.8
01
#include<bits/stdc++.h>
02
int
cp(
int
a,
int
b)
03
{
04
return
a>b;
05
}
06
using
namespace
std;
07
struct
node
08
{
09
long
long
data;
10
struct
node *next;
11
};
12
int
main()
13
{
14
int
i,sum1,sum2,d;
15
int
a[220],x[222];
16
char
s[11010];
17
while
(cin>>s)
18
{
19
memset
(a,0,
sizeof
(a));
20
sum2=0;
21
int
cnt=0;
22
for
(i=0; i<
strlen
(s); i++)
23
{
24
d=s[i];
25
a[d]++;
26
}
27
sum1=
strlen
(s)*8;
28
for
(i=0; i<130; i++)
29
{
30
if
(a[i]!=0)
31
x[cnt++]=a[i];
32
}
33
if
(cnt==1)
34
cout<<
"8 1 8.0"
<<endl;
35
else
36
{
37
sort(x,x+cnt,cp);
38
for
(i=0; cnt>1; i++)
39
{
40
sum2=x[cnt-1]+x[cnt-2]+sum2;
41
x[cnt-2]=x[cnt-1]+x[cnt-2];
42
cnt-=1;
43
sort(x,x+cnt,cp);
44
}
45
printf
(
"%d %d %.1f\n"
,sum1,sum2,sum1*1.0/sum2);
46
}
47
}
48
return
0;
49
}
01
#include<bits/stdc++.h>
02
using
namespace
std;
03
int
m,a[200005];
04
int
sw(
int
p,
int i)
交换函数
05
{
06
int
t=a[i];
07
a[i]=a[p];
08
a[p]=t;
09
}
10
void
sd(
int
i) 搜索查找左右子跟。
11
{
12
int
f=0,t;
13
while
(f==0&&i*2<=m)
14
{
15
if
(a[i*2]>a[i])
16
t=i*2;
17
else
18
t=i;
19
if
(i*2+1<=m)
20
if
(a[t]<a[i*2+1])
21
t=i*2+1;
22
if
(t!=i)
23
{
24
sw(i,t);
25
i=t;
26
}
27
else
28
f=1; 标志(如果是他本身就比左子树 。右子树都大所以不交换)
29
}
30
}
31
void
b()
32
{
33
int
k;
34
for
(k=m/2;k>=1;k--)
35
sd(k); 对M/2之前搜索就可以。
36
}
37
void
sortt()
38
{
39
while
(m>1)
40
{
41
sw(m,1);
42
m--;
43
sd(1);
44
} 每次把数组中的数放到首位进行建树。
45
}
46
int
main()
47
{
48
int
n,i,t,g,j;
49
while
(cin>>m)
50
{
51
t=m;
52
for
(i=1;i<=m;i++)
53
cin>>a[i];
54
b();
55
sortt();
56
for
(i=1;i<t;i++)
57
cout<<a[i]<<
" "
;
58
cout<<a[t]<<endl;
59
}
60
return
0;
61
}