2019天梯赛第五次训练赛

7-1 个位数统计 (15 分)

给定一个 k 位整数 N=dk-110k-1+...+d1101+d0(0<=di<=9,i=0,...k-1,dk-1>=0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 0,则有 2 个 0,3 个 1,和 1 个 3。

输入格式:

每个输入包含 1 个测试用例,即一个不超过 1000 位的正整数 N。

输出格式:

对 N 中每一种不同的个位数字,以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。

输入样例:

100311

输出样例:

0:2
1:3
3:1

0-9总共10个数,存数组统计出现次数

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int a[10];
 5 int main()
 6 {
 7     string s;
 8     cin>>s;
 9     for(int i=0;i<s.size();i++)
10         a[s[i]-'0']++;
11     for(int i=0;i<10;i++)
12         if(a[i])
13             printf("%d:%d\n",i,a[i]);
14     return 0;
15 }
7-2 What is a computer? (5 分)

本题要求编写程序,输出一个短句“What is a computer?”。

输入格式:

本题目没有输入。

输出格式:

在一行中输出短句“What is a computer?”。

水题

1 #include<bits/stdc++.h>
2 using namespace std;
3 
4 int main()
5 {
6     cout<<"What is a computer?";
7     return 0;
8 }
7-3 将x的平方赋值给y (5 分)

假设x的值为3,计算x的平方并赋值给y,分别以“y = ∗ x”和“∗ x = y”的形式输出x和y的值。

输入格式:

本题无输入

输出格式:

按照下列格式输出代入x=3的结果:

y = x * x
x * x = y

这题啥意思啊,原来是这样

1 #include<bits/stdc++.h>
2 using namespace std;
3 
4 int main()
5 {
6     cout<<"9 = 3 * 3\n3 * 3 = 9";
7     return 0;
8 }
7-5 通讯录的录入与显示 (10 分)

通讯录中的一条记录包含下述基本信息:朋友的姓名、出生日期、性别、固定电话号码、移动电话号码。 本题要求编写程序,录入N条记录,并且根据要求显示任意某条记录。

输入格式:

输入在第一行给出正整数N(<=10);随后N行,每行按照格式姓名 生日 性别 固话 手机给出一条记录。其中姓名是不超过10个字符、不包含空格的非空字符串;生日按yyyy/mm/dd的格式给出年月日;性别用M表示“男”、F表示“女”;固话手机均为不超过15位的连续数字,前面有可能出现+

在通讯录记录输入完成后,最后一行给出正整数K,并且随后给出K个整数,表示要查询的记录编号(从0到N1顺序编号)。数字间以空格分隔。

输出格式:

对每一条要查询的记录编号,在一行中按照姓名 固话 手机 性别 生日的格式输出该记录。若要查询的记录不存在,则输出Not Found

输入样例:

3
Chris 1984/03/10 F +86181779452 13707010007
LaoLao 1967/11/30 F 057187951100 +8618618623333
QiaoLin 1980/01/01 M 84172333 10086
2 1 7

输出样例:

LaoLao 057187951100 +8618618623333 F 1967/11/30
Not Found

注意范围[0,n-1]

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct p
 5 {
 6     string name,sr,sex,tel,ph;
 7 }d[15];
 8 int main()
 9 {
10     int n,k,m;
11     cin>>n;
12     for(int i=0;i<n;i++)
13         cin>>d[i].name>>d[i].sr>>d[i].sex>>d[i].tel>>d[i].ph;
14     cin>>k;
15     while(k--)
16     {
17         cin>>m;
18         if(m<0||m>=n)printf("Not Found\n");
19         else cout<<d[m].name<<" "<<d[m].tel<<" "<<d[m].ph<<" "<<d[m].sex<<" "<<d[m].sr<<endl;
20     }
21     return 0;
22 }
7-6 判断素数 (10 分)

本题的目标很简单,就是判断一个给定的正整数是否素数。

输入格式:

输入在第一行给出一个正整数N(<=10),随后N行,每行给出一个小于231​​的需要判断的正整数。

输出格式:

对每个需要判断的正整数,如果它是素数,则在一行中输出Yes,否则输出No

输入样例:

2
11
111

输出样例:

Yes
No

有人问,i*i<=n为什么是错的,i<=sqrt(n)才是对的?

考虑i等于2^31-1,i*i爆int了,平时也不用后面的因为sqrt太慢了,一般int b=sqrt(n),再循环

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 bool check(int x)
 5 {
 6     int b=sqrt(x);
 7     if(x<=1)return false;
 8     for(int i=2;i<=b;i++)
 9         if(x%i==0)return false;
10     return true;
11 }
12 int main()
13 {
14     int t,n;
15     cin>>t;
16     while(t--)
17     {
18         cin>>n;
19         if(check(n))cout<<"Yes\n";
20         else cout<<"No\n";
21     }
22     return 0;
23 }
7-4 统计一行文本的单词个数 (15 分)

本题目要求编写程序统计一行字符中单词的个数。所谓“单词”是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个。

输入格式:

输入给出一行字符。

输出格式:

在一行中输出单词个数。

输入样例:

Let's go to room 209.

输出样例:

5

你在最后加一个空格

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     string s;
 7     getline(cin,s);
 8     s+=' ';
 9     int c=0;
10     for(int i=1;i<s.size();i++)
11         if(s[i]==' '&&s[i-1]!=' ')c++;
12     printf("%d",c);
13     return 0;
14 }
7-7 打印沙漏 (20 分)

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印

*****
 ***
  *
 ***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式:

输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。

输出格式:

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例:

19 *

输出样例:

*****
 ***
  *
 ***
*****
2

中间1个先减掉,然后循环每次+2,判断上半部分有几层

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int n;
 7     char ch;
 8     scanf("%d %c",&n,&ch);
 9     n--;
10     int level=1,l=1;
11     for(int i=3;;i+=2)
12     {
13         if(n-2*i>=0)
14         {
15             n-=2*i;
16             l=i;
17         }
18         else break;
19         level++;
20     }
21     int pp=l;
22     for(int i=0;i<level;i++)
23     {
24         for(int j=0;j<i;j++)printf(" ");
25         for(int j=0;j<pp;j++)printf("%c",ch);
26         printf("\n");
27         pp-=2;
28     }
29     pp=3;
30     for(int i=level-2;i>=0;i--)
31     {
32         for(int j=0;j<i;j++)printf(" ");
33         for(int j=0;j<pp;j++)printf("%c",ch);
34         printf("\n");
35         pp+=2;
36     }
37     printf("%d",n);
38     return 0;
39 }
7-8 列出连通集 (25 分)

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:

输入第1行给出2个整数N(0<=N<=10)E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

输出格式:

按照"{ v1​​ v2​​ ... vk​​ }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

输入样例:

8 6
0 7
0 1
2 0
4 1
2 4
3 5

输出样例:

{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }

深搜广搜模板题

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int vis[15],G[15][15],n;
 5 void dfs(int u)
 6 {
 7     if(vis[u])return;
 8     vis[u]=1;
 9     printf(" %d",u);
10     for(int i=0;i<n;i++)
11         if(G[u][i]&&!vis[i])
12             dfs(i);
13 }
14 void bfs(int s)
15 {
16     queue<int>q;
17     q.push(s);
18     while(!q.empty())
19     {
20         int u=q.front();q.pop();
21         if(vis[u])continue;
22         vis[u]=1;
23         printf(" %d",u);
24         for(int i=0;i<n;i++)
25             if(G[u][i]&&!vis[i])
26                 q.push(i);
27     }
28 }
29 int main()
30 {
31     int e,u,v;
32     cin>>n>>e;
33     for(int i=0;i<e;i++)
34     {
35         cin>>u>>v;
36         G[u][v]=G[v][u]=1;
37     }
38     memset(vis,0,sizeof vis);
39     for(int i=0;i<n;i++)
40         if(!vis[i])
41         {
42             printf("{");
43             dfs(i);
44             printf(" }\n");
45         }
46     memset(vis,0,sizeof vis);
47     for(int i=0;i<n;i++)
48     {
49         if(!vis[i])
50         {
51             printf("{");
52             bfs(i);
53             printf(" }\n");
54         }
55     }
56     return 0;
57 }
7-9 整数的分类处理 (20 分)

给定 N 个正整数,要求你从中得到下列三种计算结果:

  • A1 = 能被 3 整除的最大整数
  • A2 = 存在整数 K 使之可以表示为 3K+1 的整数的个数
  • A3 = 存在整数 K 使之可以表示为 3K+2 的所有整数的平均值(精确到小数点后 1 位)

输入格式:

输入首先在第一行给出一个正整数 N,随后一行给出 N 个正整数。所有数字都不超过 100,同行数字以空格分隔。

输出格式:

在一行中顺序输出 A1、A2、A3的值,其间以 1 个空格分隔。如果某个数字不存在,则对应输出NONE

输入样例 1:

8
5 8 7 6 9 1 3 10

输出样例 1:

9 3 6.5

输入样例 2:

8
15 18 7 6 9 1 3 10

输出样例 2:

18 3 NONE

按题意模拟就行了,int/int要输出double类型得这样int*1./int

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int A1=0,A2=0,A3=0,n,a[105],c3=0;
 7     cin>>n;
 8     for(int i=1;i<=n;i++)
 9     {
10         cin>>a[i];
11         if(a[i]%3==0)A1=max(A1,a[i]);
12         if((a[i]-1)%3==0)A2++;
13         if((a[i]-2)%3==0)A3+=a[i],c3++;
14     }
15     if(A1==0)printf("NONE ");
16     else printf("%d ",A1);
17     if(A2==0)printf("NONE ");
18     else printf("%d ",A2);
19     if(A3==0)printf("NONE");
20     else printf("%.1f",A3*1./c3);
21     return 0;
22 }
7-10 树种统计 (25 分)

随着卫星成像技术的应用,自然资源研究机构可以识别每一棵树的种类。请编写程序帮助研究人员统计每种树的数量,计算每种树占总数的百分比。

输入格式:

输入首先给出正整数N(<=105),随后N行,每行给出卫星观测到的一棵树的种类名称。种类名称由不超过30个英文字母和空格组成(大小写不区分)。

输出格式:

按字典序递增输出各种树的种类名称及其所占总数的百分比,其间以空格分隔,保留小数点后4位。

输入样例:

29
Red Alder
Ash
Aspen
Basswood
Ash
Beech
Yellow Birch
Ash
Cherry
Cottonwood
Ash
Cypress
Red Elm
Gum
Hackberry
White Oak
Hickory
Pecan
Hard Maple
White Oak
Soft Maple
Red Oak
Red Oak
White Oak
Poplan
Sassafras
Sycamore
Black Walnut
Willow

输出样例:

Ash 13.7931%
Aspen 3.4483%
Basswood 3.4483%
Beech 3.4483%
Black Walnut 3.4483%
Cherry 3.4483%
Cottonwood 3.4483%
Cypress 3.4483%
Gum 3.4483%
Hackberry 3.4483%
Hard Maple 3.4483%
Hickory 3.4483%
Pecan 3.4483%
Poplan 3.4483%
Red Alder 3.4483%
Red Elm 3.4483%
Red Oak 6.8966%
Sassafras 3.4483%
Soft Maple 3.4483%
Sycamore 3.4483%
White Oak 10.3448%
Willow 3.4483%
Yellow Birch 3.4483%

样例一大堆,就是个map的功能

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 map<string,int>ma;
 5 int main()
 6 {
 7     int n;
 8     string s;
 9     cin>>n;cin.get();
10     for(int i=0;i<n;i++)
11     {
12         getline(cin,s);
13         ma[s]++;
14     }
15     for(auto X:ma)
16     {
17         cout<<X.first<<" ";
18         printf("%.4f%%\n",X.second*100./n);
19     }
20     return 0;
21 }

7-11 列车调度 (25 分)

火车站的列车调度铁轨的结构如下图所示。

两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?

输入格式:

输入第一行给出一个整数N (2 <= N <= 105),下一行给出从1到N的整数序号的一个重排列。数字间以空格分隔。

输出格式:

在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。

输入样例:
9
8 4 2 5 3 9 1 6 7
输出样例:
4

这题就是求至少需要几个最长上升子序列O(nlogn)

首先8,加入1铁路,a[1]=8;

然后4比8小,加入1铁路,a[1]=4;

然后2比4小,同上,a[1]=2;

然后5比2大,这里现有a[1]=2,新加2铁路,a[2]=5;

然后3比5小,这里现有a[1]=2,a[2]=5,找1个比3大一点点的(贪心upper_bound>x的第一个),所有加入2铁路,a[2]=3;

然后9比3大,这里现有a[1]=2,a[2]=3(这里可以发现a数组是递增的),新加3铁路,a[3]=9;

以此类推

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=1e5+5;
 5 int a[maxn];
 6 int main()
 7 {
 8     int n,x,cnt=0;
 9     cin>>n;
10     for(int i=1;i<=n;i++)
11     {
12         cin>>x;
13         if(cnt==0||a[cnt]<x)a[++cnt]=x;
14         else
15         {
16             int p=upper_bound(a+1,a+cnt+1,x)-a;
17             a[p]=x;
18         }
19     }
20     cout<<cnt;
21     return 0;
22 }
7-12 最短工期 (25 分)

一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。

输入格式:

首先第一行给出两个正整数:项目里程碑的数量 N(<=100)和任务总数 M。这里的里程碑从 0 到 N1 编号。随后 M 行,每行给出一项任务的描述,格式为“任务起始里程碑 任务结束里程碑 工作时长”,三个数字均为非负整数,以空格分隔。

输出格式:

如果整个项目的安排是合理可行的,在一行中输出最早完工时间;否则输出"Impossible"。

输入样例 1:

9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4

输出样例 1:

18

输入样例 2:

4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5

输出样例 2:

Impossible

任务之间有先后依赖顺序那么就是拓扑排序题

cost[i][j]表示i->j的花费

zao[i]表示到i点的最短时间,那么肯定存在点u与i有边,maxx为zao[u]的最大值,zao[i]=max(zao[i],maxx+cost[u][i])

vector<int>G[i]里放的是能被i到的所有点,根据拓扑排序,当一个点i入度为0,那么这个点i就可以加入队列,最后只要判断是否每个点都进入队列

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int cost[105][105],n,in[105],vis[105],zao[105];
 5 vector<int>G[105];
 6 void topu()
 7 {
 8     queue<int>q;
 9     for(int i=0;i<n;i++)
10         if(!in[i])q.push(i),vis[i]=1;
11     while(!q.empty())
12     {
13         int u=q.front();q.pop();
14         for(int i=0;i<n;i++)
15         {
16             if(cost[u][i]!=0x3f3f3f3f&&!vis[i])
17             {
18                 in[i]--;
19                 if(!in[i])
20                 {
21                     int maxx=0;
22                     for(int j=0;j<G[i].size();j++)
23                         maxx=max(maxx,zao[G[i][j]]);
24                     for(int j=0;j<G[i].size();j++)
25                         if(maxx==zao[G[i][j]])
26                             zao[i]=max(zao[i],maxx+cost[G[i][j]][i]);
27                     vis[i]=1;
28                     q.push(i);
29                 }
30             }
31         }
32     }
33     int f=1,maxx=0;
34     for(int i=0;i<n;i++)
35     {
36         if(!vis[i])f=0;
37         maxx=max(maxx,zao[i]);
38     }
39     if(f)printf("%d",maxx);
40     else printf("Impossible");
41 }
42 int main()
43 {
44     memset(cost,0x3f,sizeof cost);
45     int m,u,v,t;
46     cin>>n>>m;
47     for(int i=0;i<n;i++)cost[i][i]=0;
48     for(int i=0;i<m;i++)
49     {
50         cin>>u>>v>>t;
51         cost[u][v]=min(t,cost[u][v]);
52         G[v].push_back(u);
53         in[v]++;
54     }
55     topu();
56     return 0;
57 }
58 /*
59 4 3
60 0 3 4
61 0 2 3
62 0 1 3
63 */
7-13 地下迷宫探索 (30 分)

地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式。地道网是房连房、街连街、村连村的地下工事,如下图所示。

我们在回顾前辈们艰苦卓绝的战争生活的同时,真心钦佩他们的聪明才智。在现在和平发展的年代,对多数人来说,探索地下通道或许只是一种娱乐或者益智的游戏。本实验案例以探索地下通道迷宫作为内容。

假设有一个地下通道迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关。请问你如何从某个起点开始在迷宫中点亮所有的灯并回到起点?

输入格式:

输入第一行给出三个正整数,分别表示地下迷宫的节点数N(1<N<=1000,表示通道所有交叉点和端点)、边数M(<=3000),表示通道数

和探索起始节点编号S(节点从1到N编号)。随后的M行对应M条边(通道),每行给出一对正整数,分别是该条边直接连通的两个节点的编号。

输出格式:

若可以点亮所有节点的灯,则输出从S开始并以S结束的包含所有节点的序列,序列中相邻的节点一定有边(通道);否则虽然不能点亮所有节点的灯,但还是输出点亮部分灯的节点序列,最后输出0,此时表示迷宫不是连通图。

由于深度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以节点小编号优先的次序访问(点灯)。在点亮所有可以点亮的灯后,以原路返回的方式回到起点。

输入样例1:

6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5

输出样例1:

1 2 3 4 5 6 5 4 3 2 1

输入样例2:

6 6 6
1 2
1 3
2 3
5 4
6 5
6 4

输出样例2:

6 4 5 4 6 0

代码里的递归理解下,dfs(i)下的输出就是深搜依次遍历的点(倒着输出,就是路径)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int vis[1005],G[1005][1005],n,s;
 5 void dfs(int u)
 6 {
 7     if(vis[u])return;
 8     vis[u]=1;
 9     if(u==s)printf("%d",u);
10     else printf(" %d",u);
11     for(int i=1;i<=n;i++)
12     {
13         if(G[u][i]&&!vis[i])
14         {
15             dfs(i);
16             printf(" %d",u);
17         }
18     }
19     
20 }
21 int main()
22 {
23     int m,u,v;
24     cin>>n>>m>>s;
25     for(int i=0;i<m;i++)
26     {
27         cin>>u>>v;
28         G[u][v]=G[v][u]=1;
29     }
30     dfs(s);
31     for(int i=1;i<=n;i++)
32         if(!vis[i])
33         {
34             printf(" 0");
35             break;
36         }
37     return 0;
38 }
7-14 天梯地图 (30 分)

本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。

输入格式:

输入在第一行给出两个正整数N(2<=N<=500)M,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M行,每行按如下格式给出一条道路的信息:

V1 V2 one-way length time

其中V1V2是道路的两个端点的编号(从0到N-1);如果该道路是从V1V2的单行线,则one-way为1,否则为0;length是道路的长度;time是通过该路所需要的时间。最后给出一对起点和终点的编号。

输出格式:

首先按下列格式输出最快到达的时间T和用节点编号表示的路线:

Time = T: 起点 => 节点1 => ... => 终点

然后在下一行按下列格式输出最短距离D和用节点编号表示的路线:

Distance = D: 起点 => 节点1 => ... => 终点

如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。

如果这两条路线是完全一样的,则按下列格式输出:

Time = T; Distance = D: 起点 => 节点1 => ... => 终点

输入样例1:

10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
5 4 0 2 3
5 9 1 1 4
0 6 0 1 1
7 3 1 1 2
8 3 1 1 2
2 5 0 2 2
2 1 1 1 1
1 5 0 1 3
1 4 0 1 1
9 7 1 1 3
3 1 0 2 5
6 3 1 2 1
5 3

输出样例1:

Time = 6: 5 => 4 => 8 => 3
Distance = 3: 5 => 1 => 3

输入样例2:

7 9
0 4 1 1 1
1 6 1 3 1
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 3 1
3 2 1 2 1
4 5 0 2 2
6 5 1 2 1
3 5

输出样例2:

Time = 3; Distance = 4: 3 => 2 => 5

哈夫曼编码拿了29分一直找不到问题就来肝这个题了,是个最短路输出路径,码量有点大

1.首先输出到E最快时间,若不唯一则输出距离最短的,保证唯一

2.然后输出到E最短距离,若不唯一则输出经过点数最少的,保证唯一

3.判断1和2的路径是否一样,sort后比较,若一样则输出,不一样输出1,2

分模块写,写一点测一点,时间有点紧288ms(300ms)卡过,这个dij不是很优秀

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define fi first
  5 #define se second
  6 int Glen[505][505];
  7 int Gtime[505][505];
  8 bool Garr[505][505];
  9 vector<int>out1,out2;
 10 int acT,acL,n,m,S,E;
 11 int TL[1005],C[1005],pre[1005];
 12 queue<int>q;
 13 void init()
 14 {
 15     while(!q.empty())q.pop();
 16     for(int i=0;i<n;i++)
 17         TL[i]=C[i]=0x3f3f3f3f,pre[i]=-1;
 18     TL[S]=C[S]=0;
 19 }
 20 vector<int>road()
 21 {
 22     int R=E;
 23     vector<int>way,ro;
 24     while(R!=-1)
 25     {
 26         way.push_back(R);
 27         R=pre[R];
 28     }
 29     for(int i=(int)way.size()-1;i>=0;i--)
 30         ro.push_back(way[i]);
 31     return ro;
 32 }
 33 void dij1()//最快 相同最短
 34 {
 35     init();
 36     q.push(S);
 37     while(!q.empty())
 38     {
 39         int u=q.front();q.pop();
 40         for(int v=0;v<n;v++)
 41         {
 42             if(!Garr[u][v])continue;
 43             if(TL[v]>TL[u]+Gtime[u][v])
 44             {
 45                 TL[v]=TL[u]+Gtime[u][v];
 46                 pre[v]=u;
 47                 C[v]=C[u]+Glen[u][v];
 48                 q.push(v);
 49             }
 50             else if(TL[v]==TL[u]+Gtime[u][v]&&C[v]>C[u]+Glen[u][v])
 51             {
 52                 C[v]=C[u]+Glen[u][v];
 53                 pre[v]=u;
 54                 q.push(v);
 55             }
 56         }
 57     }
 58     acT=TL[E],out1=road();
 59 }
 60 void dij2()//最短距离 最少点数
 61 {
 62     init();
 63     q.push(S);
 64     while(!q.empty())
 65     {
 66         int u=q.front();q.pop();
 67         for(int v=0;v<n;v++)
 68         {
 69             if(!Garr[u][v])continue;
 70             if(TL[v]>TL[u]+Glen[u][v])
 71             {
 72                 TL[v]=TL[u]+Glen[u][v];
 73                 C[v]=C[u]+1;
 74                 pre[v]=u;
 75                 q.push(v);
 76             }
 77             else if(TL[v]==TL[u]+Glen[u][v]&&C[v]>C[u]+1)
 78             {
 79                 C[v]=C[u]+1;
 80                 pre[v]=u;
 81                 q.push(v);
 82             }
 83         }
 84     }
 85     acL=TL[E],out2=road();
 86 }
 87 int main()
 88 {
 89     memset(Glen,0x3f,sizeof Glen);
 90     memset(Gtime,0x3f,sizeof Gtime);   
 91     cin>>n>>m;
 92     for(int i=0;i<n;i++)Glen[i][i]=Gtime[i][i]=0;
 93     for(int i=0;i<m;i++)
 94     {
 95         int u,v,oneway,len,time;
 96         cin>>u>>v>>oneway>>len>>time;
 97         Glen[u][v]=len;
 98         Gtime[u][v]=time;
 99         Garr[u][v]=1;
100         if(!oneway)
101         {
102             Glen[v][u]=len;
103             Gtime[v][u]=time;
104             Garr[v][u]=1;
105         }
106     }
107     cin>>S>>E;
108     dij1(),dij2();
109     vector<int>sortA=out1,sortB=out2;
110     sort(sortA.begin(),sortA.end());
111     sort(sortB.begin(),sortB.end());
112     int same=1;
113     if((int)sortA.size()==(int)sortB.size())
114     {
115         for(int i=0;i<sortA.size();i++)
116         {
117             if(sortA[i]!=sortB[i])
118             {
119                 same=0;
120                 break;
121             }
122         }
123     }
124     else same=0;
125     if(same)
126     {
127         printf("Time = %d; Distance = %d:",acT,acL);
128         for(int i=0;i<(int)out1.size()-1;i++)
129             printf(" %d =>",out1[i]);
130         printf(" %d",out1[(int)out1.size()-1]);
131     }
132     else
133     {
134         printf("Time = %d:",acT);
135         for(int i=0;i<(int)out1.size()-1;i++)
136             printf(" %d =>",out1[i]);
137         printf(" %d\n",out1[(int)out1.size()-1]);
138         printf("Distance = %d:",acL);
139         for(int i=0;i<(int)out2.size()-1;i++)
140             printf(" %d =>",out2[i]);
141         printf(" %d\n",out2[(int)out2.size()-1]);
142     }
143     return 0;
144 }
7-15 哈夫曼编码 (30 分)

给定一段文字,如果我们统计出字母出现的频率,是可以根据哈夫曼算法给出一套编码,使得用此编码压缩原文可以得到最短的编码总长。然而哈夫曼编码并不是唯一的。例如对字符串"aaaxuaxz",容易得到字母 'a'、'x'、'u'、'z' 的出现频率对应为 4、2、1、1。我们可以设计编码 {'a'=0, 'x'=10, 'u'=110, 'z'=111},也可以用另一套 {'a'=1, 'x'=01, 'u'=001, 'z'=000},还可以用 {'a'=0, 'x'=11, 'u'=100, 'z'=101},三套编码都可以把原文压缩到 14 个字节。但是 {'a'=0, 'x'=01, 'u'=011, 'z'=001} 就不是哈夫曼编码,因为用这套编码压缩得到 00001011001001 后,解码的结果不唯一,"aaaxuaxz" 和 "aazuaxax" 都可以对应解码的结果。本题就请你判断任一套编码是否哈夫曼编码。

输入格式:

首先第一行给出一个正整数 N(2<=N<=63),随后第二行给出 N 个不重复的字符及其出现频率,格式如下:

c[1] f[1] c[2] f[2] ... c[N] f[N]

其中c[i]是集合{'0' - '9', 'a' - 'z', 'A' - 'Z', '_'}中的字符;f[i]c[i]的出现频率,为不超过 1000 的整数。再下一行给出一个正整数 M(<=1000),随后是 M 套待检的编码。每套编码占 N 行,格式为:

c[i] code[i]

其中c[i]是第i个字符;code[i]是不超过63个'0'和'1'的非空字符串。

输出格式:

对每套待检编码,如果是正确的哈夫曼编码,就在一行中输出"Yes",否则输出"No"。

注意:最优编码并不一定通过哈夫曼算法得到。任何能压缩到最优长度的前缀编码都应被判为正确。

输入样例:

7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11

输出样例:

Yes
Yes
No
No

哈夫曼树最小带权路径长度,丢了一分不够细心

考虑每个点的贡献,一个点向上合并到树根,那么贡献为所在层数*点权,就是每次在优先队列中取两个最小的值合并,最后答案就是哈夫曼树最小带权路径长度

然后哈夫曼树的最优前缀编码是不能出现前缀的,也就是样例4中E=00,A=00000

#include<bits/stdc++.h>
using namespace std;

char z[65][1005];
int n,t,len[65],a[65];

int main()
{
    scanf("%d",&n);
    priority_queue< int,vector<int>,greater<int> >q;
    for(int i=1;i<=n;i++)
    {
        scanf("%*s%d",&a[i]);
        q.push(a[i]);
    }
    int sum=0;//哈夫曼树最小带权路径长度
    while(q.size()>1)
    {
        int a=q.top();q.pop();
        int b=q.top();q.pop();
        sum+=a+b;
        q.push(a+b);
    }
    scanf("%d",&t);
    while(t--)
    {
        int val=0,f=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%*s%s",z[i]);
            len[i]=strlen(z[i]);
            if(!f)continue;
            for(int j=1;j<i;j++)//是否存在前缀
            {
                int MinLen=min(len[i],len[j]),flag=1;
                for(int k=0;flag&&k<MinLen;k++)
                    if(z[i][k]!=z[j][k])
                        flag=0;
                if(flag)
                {
                    f=0;
                    break;
                }
            }
            val+=len[i]*a[i];
        }
        if(f&&val==sum)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

posted on 2019-03-02 20:29  大桃桃  阅读(2403)  评论(0编辑  收藏  举报

导航