7-1 求链式线性表的倒数第K项
给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。
输入格式:
输入首先给出一个正整数K,随后是若干非负整数,最后以一个负整数表示结尾(该负数不算在序列内,不要处理)。
输出格式:
输出倒数第K个位置上的数据。如果这个位置不存在,输出错误信息NULL
。
输入样例:
4 1 2 3 4 5 6 7 8 9 0 -1
输出样例:
7
解题思路:首先存入所有的数据,注意负整数不能存,注意最终跳出NULL的条件,保证k在数组的范围中就行
#include<iostream>
#include<vector>
using namespace std;
int k;
vector<int>v;
int main()
{
cin >> k;
while(1)
{
int num;
cin >> num;
if(num < 0) break;
v.push_back(num);
}
int n = v.size();
if(k < 0 || k > n)
{
puts("NULL");
return 0;
}
cout << v[n - k] << endl;
return 0;
}
7-2 两个有序链表序列的交集
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例:
1 2 5 -1
2 4 5 8 10 -1
输出样例:
2 5
解题思路:用哈希表存第一个表每一个数的个数,再遍历第二个表,找到重复的即可,注意可能会有连续好几个一样的不能使用unordered_set去存
#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
unordered_map<int , int>mp;
vector<int>res;
int main()
{
while(1)
{
int num;
cin >> num;
if(num == -1) break;
mp[num] ++;
}
while(1)
{
int num;
cin >> num;
if(num == -1) break;
if(mp[num]) res.push_back(num) , mp[num] --;
}
if(!res.size()) puts("NULL");
else
{
for(int i = 0;i < res.size();i ++)
{
if(i) cout << " ";
cout << res[i];
}
//cout << endl;
}
return 0;
}
7-3 多项式A除以B(仔细看这道题其实是天梯赛的题)
这也是这四道题中最难的一道题了
这仍然是一道关于A/B的题,只不过A和B都换成了多项式。你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数。
输入格式:
输入分两行,每行给出一个非零多项式,先给出A,再给出B。每行的格式如下:
N e[1] c[1] ... e[N] c[N]
其中N
是该多项式非零项的个数,e[i]
是第i
个非零项的指数,c[i]
是第i
个非零项的系数。各项按照指数递减的顺序给出,保证所有指数是各不相同的非负整数,所有系数是非零整数,所有整数在整型范围内。
输出格式:
分两行先后输出商和余,输出格式与输入格式相同,输出的系数保留小数点后1位。同行数字间以1个空格分隔,行首尾不得有多余空格。注意:零多项式是一个特殊多项式,对应输出为0 0 0.0
。但非零多项式不能输出零系数(包括舍入后为0.0)的项。在样例中,余多项式其实有常数项-1/27
,但因其舍入后为0.0,故不输出。
输入样例:
4 4 1 2 -3 1 -1 0 -1
3 2 3 1 -2 0 1
输出样例:
3 2 0.3 1 0.2 0 -1.0
1 1 -3.1
解题思路:
第一点就是,得弄清楚多项式怎么除
需要计算的每一个数有两个值需要求一个是指数一个是系数
指数的求法就是被除数的第i个指数减除数的第i个的指数
系数求法就是被除数的第i个除以除数第i个系数将商第i项去乘除式,把积写在被除式下面(同类项对齐),消去相等项,把不相等的项结合起来,就是需要更新的数
第二点就是,怎么存
哈希表和结构体去存每一个除数和被除数,注意最终结果剩下的余数一定是被除数(无法被再除)
最后就是怎么表达了
#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int N = 1e5 + 10;
unordered_map<int , double>A , res;
struct nodes
{
int e;// 指数
double c;// 系数
}B[N];
bool check(double x)
{
if(x > 0 && x >= 0.05) return true;
else if(x < 0 && x <= -0.05) return true;
return false;
}
void print(int t , int w , int m)
{
if(!w)
{
cout << " 0 0.0";
return;
}
if(!t) // 商
{
for(int i = m;i >= 0;i --)
{
int x = i;
double y = res[i];
if(check(y)) printf(" %d %.1lf" , x, y);
}
}
else
{
for(int i = m;i >= 0;i --)
{
int x = i;
double y = A[i];
if(check(y)) printf(" %d %.1lf" ,x, y);
}
}
}
int main()
{
int _max = -1;
int cnt = 0;
for(int i = 0;i < 2;i ++)
{
int k;
cin >> k;
while(k --)
{
int a;
double b;
cin >> a >> b;
if(!i) A[a] = b , _max = max(_max , a);
else B[cnt].e = a , B[cnt ++].c = b;
}
}
// 得到的数有两个一个是指数一个是系数
// 指数的求法就是被除数的第i个指数减除数的第i个的指数
// 系数求法就是被除数的第i个除以除数第i个系数
for(int i = _max;i >= B[0].e;i --)
{
int x_e = i - B[0].e;
double x_c = A[i] / B[0].c;
res[x_e] = x_c;
for(int j = 0;j < cnt;j ++)
A[B[j].e + x_e] -= x_c * B[j].c;
}
// A就是余数 , res就是商
int cnt_r = 0 , cnt_q = 0;
for(int i = 0;i <= _max;i ++)
{
double x = res[i];
double y = A[i];
if(check(x)) cnt_q ++;
if(check(y)) cnt_r ++;
}
// 商的输出
cout << cnt_q;
print(0 , cnt_q , _max);
cout << endl;
// 余数的输出
cout << cnt_r;
print(1 , cnt_r , _max);
}
7-4 喊山
喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤。呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的。原来它是彝族先民用来求援呼救的“讯号”,慢慢地人们在生活实践中发现了它的实用价值,便把它作为一种交流工具世代传袭使用。(忽略人的照片)
一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。
输入格式:
输入第一行给出3个正整数n
、m
和k
,其中n
(≤10000)是总的山头数(于是假设每个山头从1到n
编号)。接下来的m
行,每行给出2个不超过n
的正整数,数字间用空格分开,分别代表可以听到彼此的两个山头的编号。这里保证每一对山头只被输入一次,不会有重复的关系输入。最后一行给出k
(≤10)个不超过n
的正整数,数字间用空格分开,代表需要查询的山头的编号。
输出格式:
依次对于输入中的每个被查询的山头,在一行中输出其发出的呼喊能够连锁传达到的最远的那个山头。注意:被输出的首先必须是被查询的个山头能连锁传到的。若这样的山头不只一个,则输出编号最小的那个。若此山头的呼喊无法传到任何其他山头,则输出0。
输入样例:
7 5 4
1 2
2 3
3 1
4 5
5 6
1 4 5 7
输出样例:
2
6
4
0
解题思路: 这道题要求的就是离给定询问距离最远并且编号最小的山头的编号,一开始想的是并查集,显然并查集是写不出来的,因为询问都是一个点,并且返回的结果并不是,这个节点的祖宗节点,而是距离最远并且编号最小的山头,然后应该想到的就是bfs,计算出每一个给定询问的和每个相邻节点的距离,最终遍历一遍距离数组即可得到答案
bfs用什么实现?应该用队列,对于每一个节点不能重复遍历,需要有一个st去标记,在每一轮计算距离的时候,顺便计算一下最大距离,一边下边使用。
#include<iostream>
#include<unordered_map>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e5 + 10 , INF = 0x3f3f3f3f;
int n , m , k;
unordered_map<int , vector<int>>mp;
bool st[N];
queue<int>q;
int dist[N];
void bfs(int u)
{
int max_dist = -1;
while(!q.empty())
{
int t = q.front();
q.pop();
st[t] = true;
max_dist = max(max_dist , dist[t]);
for(int i : mp[t])
{
if(!st[i] && !dist[i])
{
dist[i] = dist[t] + 1;
q.push(i);
}
}
}
//cout << max_dist << endl;
for(int i = 0;i <= n;i ++)
if(dist[i] == max_dist)
{
cout << i << endl;
return ;
}
}
int main()
{
memset(st , false , sizeof st);
cin >> n >> m >> k;
for(int i = 0;i < m;i ++)
{
int a , b;
cin >> a >> b;
// 注意是无向图
mp[a].push_back(b);
mp[b].push_back(a);
}
while(k --)
{
int a;
cin >> a;
memset(st , false , sizeof st);
memset(dist , 0 , sizeof dist);
q.push(a);
bfs(a);
}
return 0;
}