seventh!(堆)(字典树)


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;

树-堆结构练习——合并果子之哈夫曼树

 
 
Time Limit: 1000MS  Memory Limit: 65536KB
Problem 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 9
Example Output
15

  
  
链表代码:
   
   
001#include<bits/stdc++.h>
002using namespace std;
003int f;
004struct node
005{
006int data;
007struct node *next;
008};
009int main()
010{
011int n,z,i,sum=0;
012struct node *p,*head,*q1,*q2,*p1,*p2;
013head=new node;
014head->next=NULL;
015cin>>n;
016if(n==1)
017{
018cin>>z;
019cout<<z<<endl;
020}
021else
022{
023p=new node;
024cin>>p->data;
025p->next=NULL;//建一个结点。
026//每当有新的数输入就建造一个新的结点,
027//头结点为空用来链接这个链表(主要是用来链接第一个结点)
028head->next=p;//(进行链表的链接。)
029for(i=2;i<=n;i++)
030{
031p=new node;
032cin>>p->data;
033q1=head;//这一步是准备遍历链表按照顺序插入了;
034q2=head->next;//两个游动指针才能插入一个新的结点。
035while(q2)
036{
037if(q2->data>p->data)
038{
039q1->next=p;
040p->next=q2;
041break;
042}
043else
044{
045q1=q1->next;
046q2=q2->next;
047}
048}
049if(q1->next==NULL)
050q1->next=p;//如果找到链表末尾都没有找到更大的值
051//就直接把这个值放在表尾。
052}
053p1=head;
054p2=head->next;
055 
056//再次使用两个游动指针。
057 
058while(p2->next!=NULL)
059{
060p1=p1->next;
061p2=p2->next;
062//两个游动指针是用来遍历 ,
063sum+=p1->data+p2->data;//求和。
064p=new node;//求和之后重复新节点的建立
065p->data=p1->data+p2->data;//新节点的数据域等于上两个的和
066p->next=NULL;
067q1=p2;
068q2=p2->next;//使用两个游动指针把新建好的结点插入合适位置形成有序链表。
069while(q2)
070{
071if(q2->data>p->data)
072{
073q1->next=p;
074p->next=q2;
075break;
076}
077else
078{
079q1=q1->next;
080q2=q2->next;
081}
082}
083if(q1->next==NULL)
084q1->next=p;//重复(没有找到比他大的就往最后面插入)
085p1=p1->next;
086p2=p2->next;
087}
088cout<<sum<<endl;
089}
090return 0;
091}

#include<bits/stdc++.h>
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;
}

字典树

Time Limit: 1000MS  Memory Limit: 65536KB
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>
02using namespace std;
03int f;
04struct node
05{
06char data[28];
07struct node *l,*r;
08};
09struct node*creat(struct node*root,char ch[])//建立字典树唯一
10//不同于有序二叉树之处就是字符串的链接
11{
12if(root==NULL)
13{
14root=new(node);
15root->l=root->r=NULL;
16strcpy(root->data,ch);
17}
18else
19{
20if(strcmp(ch,root->data)<0)
21root->l=creat(root->l,ch);
22else
23root->r=creat(root->r,ch);
24}
25return root;
26}
27void searchtree(struct node*root,char s[])
28{
29if(root)
30{
31if(strcmp(root->data,s)>0)
32searchtree(root->l,s);
33else if(strcmp(root->data,s)<0)
34searchtree(root->r,s);
35else
36f=1;
37}
38}
39int main()
40{
41int n,m;
42char a[12],s[12];
43while(cin>>n>>m)
44{
45if(n==0&&m==0)
46break;
47struct node*t;
48t=NULL;
49while(n--)
50{
51cin>>a;
52t=creat(t,a);
53}
54while(m--)
55{
56cin>>s;
57f=0;
58searchtree(t,s);
59if(f==1)
60cout<<"Yes"<<endl;
61else
62cout<<"No"<<endl;
63}
64}
65    return 0;
66}

Fence Repair

Time Limit: 2000MS  Memory Limit: 65536KB
Problem Description
Line 1: One integer N 
Line 1: One integer: the minimum amount of money he must spend to make N
Example Input
3
8
5
8
Example Output
34

  
  
01#include<bits/stdc++.h>
02using namespace std;
03struct node
04{
05long long  data;
06struct node *next;
07};
08int main()
09{
10long long n,z,i,sum=0;
11struct node *p,*head,*q1,*q2,*p1,*p2;
12head=new node;
13head->next=NULL;
14cin>>n;
15if(n==1)
16{
17cin>>z;
18cout<<z<<endl;
19}
20else
21{
22p=new node;
23cin>>p->data;
24p->next=NULL;//建一个结点。
25//每当有新的数输入就建造一个新的结点,
26//头结点为空用来链接这个链表(主要是用来链接第一个结点)
27head->next=p;//(进行链表的链接。)
28for(i=2;i<=n;i++)
29{
30p=new node;
31cin>>p->data;
32q1=head;//这一步是准备遍历链表按照顺序插入了;
33q2=head->next;//两个游动指针才能插入一个新的结点。
34while(q2)
35{
36if(q2->data>p->data)
37{
38q1->next=p;
39p->next=q2;
40break;
41}
42else
43{
44q1=q1->next;
45q2=q2->next;
46}
47}
48if(q1->next==NULL)
49q1->next=p;//如果找到链表末尾都没有找到更大的值
50//就直接把这个值放在表尾。
51}
52p1=head;
53p2=head->next;
54 
55//再次使用两个游动指针。
56 
57while(p2->next!=NULL)
58{
59p1=p1->next;
60p2=p2->next;
61//两个游动指针是用来遍历 ,
62sum+=p1->data+p2->data;//求和。
63p=new node;//求和之后重复新节点的建立
64p->data=p1->data+p2->data;//新节点的数据域等于上两个的和
65p->next=NULL;
66q1=p2;
67q2=p2->next;//使用两个游动指针把新建好的结点插入合适位置形成有序链表。
68while(q2)
69{
70if(q2->data>p->data)
71{
72q1->next=p;
73p->next=q2;
74break;
75}
76else
77{
78q1=q1->next;
79q2=q2->next;
80}
81}
82if(q1->next==NULL)
83q1->next=p;//重复(没有找到比他大的就往最后面插入)
84p1=p1->next;
85p2=p2->next;
86}
87cout<<sum<<endl;
88}
89return 0;
90}

数据结构实验之二叉树六:哈夫曼编码

Time Limit: 1000MS Memory Limit: 65536KB
Problem Description

字符的编码方式有多种,除了大家熟悉的ASCII编码,哈夫曼编码(Huffman Coding)也是一种编码方式,它是可变字长编码。该方法完全依据字符出现概率来构造出平均长度最短的编码,称之为最优编码。哈夫曼编码常被用于数据文件压缩中,其压缩率通常在20%90%之间。你的任务是对从键盘输入的一个字符串求出它的ASCII编码长度和哈夫曼编码长度的比值。

Input
 输入数据有多组,每组数据一行,表示要编码的字符串。
Output
 对应字符的 ASCII 编码长度 la huffman 编码长度 lh la/lh 的值 ( 保留一位小数 ) ,数据之间以空格间隔。
Example Input
AAAAABCD
THE_CAT_IN_THE_HAT
Example Output
64 13 4.9
144 51 2.8

  
  
01#include<bits/stdc++.h>
02int cp(int a,int b)
03{
04    return a>b;
05}
06using namespace std;
07struct node
08{
09    long long  data;
10    struct node *next;
11};
12int 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>
02using namespace std;
03int m,a[200005];
04int sw(int p,int i) 交换函数 
05{
06int t=a[i];
07a[i]=a[p];
08a[p]=t;
09}
10void sd(int i) 搜索查找左右子跟。
11{
12int f=0,t;
13while(f==0&&i*2<=m)
14{
15if(a[i*2]>a[i])
16t=i*2;
17else
18t=i;
19if(i*2+1<=m)
20if(a[t]<a[i*2+1])
21t=i*2+1;
22if(t!=i)
23{
24sw(i,t);
25i=t;
26}
27else
28f=1; 标志(如果是他本身就比左子树 。右子树都大所以不交换)
29
30}
31void b()
32{
33int k;
34for(k=m/2;k>=1;k--)
35sd(k); 对M/2之前搜索就可以。
36}
37void sortt()
38{
39while(m>1)
40{
41sw(m,1);
42m--;
43sd(1);
44} 每次把数组中的数放到首位进行建树。
45}
46int main()
47{
48int n,i,t,g,j;
49while(cin>>m)
50{
51t=m;
52for(i=1;i<=m;i++)
53cin>>a[i];
54b();
55sortt();
56for(i=1;i<t;i++)
57cout<<a[i]<<" ";
58cout<<a[t]<<endl;
59}
60return 0;
61}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值