7-1 高精度数加法 (100 分)
高精度数是指大大超出了标准数据类型能表示的范围的数,例如10000位整数。很多计算问题的结果都很大,因此,高精度数极其重要。
一般使用一个数组来存储高精度数的所有数位,数组中的每个元素存储该高精度数的1位数字或多位数字。 请尝试计算:N个高精度数的加和。这个任务对于在学习数据结构的你来说应该是小菜一碟。 。
输入格式
第1行,1个整数N,表示高精度整数的个数,(1≤N≤10000)。
第2至N+1行,每行1个高精度整数x, x最多100位
输出格式
1行,1个高精度整数,表示输入的N个高精度数的加和。
输入样例
3
12345678910
12345678910
12345678910
输出样例
37037036730
注意
注意每次计算之后进位清零。
代码
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
void fanxu(char num0[],char cpy0[])
{
int len,i,j;
len=strlen(num0);
for(i=0,j=len-1;i<len;i++,j--)
{
cpy0[i]=num0[j];
}
cpy0[len]='\0';
strcpy(num0,cpy0);
}
char a[1000],b[1000],c[1000];
int main()
{
int i,j,len_a,len_b,bwei=0,jwei=0;
int num;
scanf("%d",&num);
cin>>a;
if(num==1)
{
cout<<a;
return 0;}
for(int k=1;k<num;k++)
{
cin>>b;
fanxu(a,c);
fanxu(b,c);
len_a=strlen(a);len_b=strlen(b);
for(i=0;i<len_a&&i<len_b;i++)
{
bwei=jwei+(a[i]-'0')+(b[i]-'0');
if(bwei>=10)
{
jwei=1;
bwei-=10;
}
else jwei=0;
c[i]=bwei+'0';
}
if(len_a>len_b)
{
for(;i<len_a;i++)
{
bwei=a[i]+jwei-'0';
if(bwei>=10)
{
jwei=1;
bwei-=10;
}
else jwei=0;
c[i]=bwei+'0';
}
}
if(len_b>len_a)
{
for(;i<len_b;i++)
{
bwei=b[i]+jwei-'0';
if(bwei>=10)
{
jwei=1;
bwei-=10;
}
else jwei=0;
c[i]=bwei+'0';
}
}
if(jwei==1) c[i++]='1';
jwei=0;
c[i]='\0';
memset(a,0,sizeof(char)*1000);
memset(b,0,sizeof(char)*1000);
fanxu(c,a);
strcpy(a,c);
}
cout<<c;
return 0;
}
7-2 二叉树加权距离 (100 分)
二叉树结点间的一种加权距离定义为:上行方向的变数×3 +下行方向的边数×2 。上行方向是指由结点向根的方向,下行方向是指与由根向叶结点方向。 给定一棵二叉树T及两个结点u和v,试求u到v的加权距离。
输入格式
第1行,1个整数N,表示二叉树的结点数,(1≤N≤100000)。
随后若干行,每行两个整数a和b,用空格分隔,表示结点a到结点b有一条边,a、b是结点的编号,1≤a、b≤N;根结点编号为1,边从根向叶结点方向。
最后1行,两个整数u和v,用空格分隔,表示所查询的两个结点的编号,1≤u、v≤N。
输出格式
1行,1个整数,表示查询的加权距离
输入样例
5
1 2
2 3
1 4
4 5
3 4
输出样例
8
思路
1.求出两点的最近公共祖先,在每个结点内部都保存一个当前结点的深度,这样,最近公共祖先深度减去出发点等于上行距离,减去终点深度等于下行距离。
2.注意两点中一点为另一点的祖先的情况。
代码
#include <stdio.h>
#include <iostream>
#include <deque>
#include <string.h>
using namespace std;
struct tree{
int num;
int tall;
struct tree *father;
struct tree *left;
struct tree *right;
};
typedef struct tree tree;
int ff,ee,up,down;
tree t[100005];
int main()
{
int num;
cin>>num;
for(int i=1;i<num;i++)
{
int f,s;
cin>>f>>s;
if(t[f].left==NULL) t[f].left=&t[s];
else t[f].right=&t[s];
t[s].father=&t[f];
t[s].tall=t[f].tall+1;
}
cin>>ff>>ee;
tree *f1=&t[ff],*f2=&t[ee];
while(f1!=f2)
{
if(f1->tall>f2->tall)
{
f1=f1->father;
}
else f2=f2->father;
}
int all=0;
if(f1==&t[ff]) all=-(f1->tall-t[ee].tall)*2;
else if(f2==&t[ee]) all=-(f1->tall-t[ff].tall)*3;
else all=-(f1->tall-t[ff].tall)*3-(f1->tall-t[ee].tall)*2;
cout<<all;
}
7-3 修轻轨 (100 分)
长春市有n个交通枢纽,计划在1号枢纽到n号枢纽之间修建一条轻轨。轻轨由多段隧道组成,候选隧道有m段。每段候选隧道只能由一个公司施工,施工天数对各家公司一致。有n家施工公司,每家公司同时最多只能修建一条候选隧道。所有公司可以同时开始施工。请评估:修建这条轻轨最少要多少天。。
输入格式
第1行,两个整数n和m,用空格分隔,分别表示交通枢纽的数量和候选隧道的数量,1 ≤ n ≤ 100000,1 ≤ m ≤ 200000。
第2行到第m+1行,每行三个整数a、b、c,用空格分隔,表示枢纽a和枢纽b之间可以修建一条双向隧道,施工时间为c天,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000000。
输出格式
输出一行,包含一个整数,表示最少施工天数。
输入样例
6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6
输出样例
6
思路与证明
1.假设从节点1到节点n有多条最短路,那么本题求的是其中边最大值最小的最短路,课通过最小生成树算法和单元最短路算法求得。
(1)kruskal算法:当最小生成树产生的时候,节点1和节点n必然是联通的,根据kruskal算法的选边的原则,那么最小生成树内包含的从1到n的路的边的最大值必然是最小的。
(2)dijistal算法:基础的dijistal算法求出的从1到n的路是总长度最小的路,而不能保证边的最大值在所有的路中最小,所以将dis数组内的值保存为这条边所在的路中的最大权值,每次找最小的权值做更新。
代码
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 500005;//点数最大值
const int INF = 100005;
int n, m, cnt;//n个点,m条边
typedef struct Edge
{
int u, to, w, next;//起点,终点,边权,同起点的上一条边的编号
} Edge;
Edge edge[2 * maxn];//边集
int head[maxn];//head[i],表示以i为起点的第一条边在边集数组的位置(编号)
void init()//初始化
{
for (int i = 0; i <= n; i++) head[i] = -1;
cnt = 0;
}
void add_edge(int u, int v, int w)//加边,u起点,v终点,w边权
{
edge[cnt].u = u;
edge[cnt].to = v; //终点
edge[cnt].w = w; //权值
edge[cnt].next = head[u];//以u为起点上一条边的编号,也就是与这个边起点相同的上一条边的编号
head[u] = cnt++;//更新以u为起点上一条边的编号
}
//kruskal算法
int father[INF];
int FIND(int x)
{
while (father[x] > 0) x = father[x];
return x;
}
void MAKE_SET(int x)
{
father[x] = 0;
}
void UNION(int x, int y)
{
int fx = FIND(x), fy = FIND(y);
if (fx == fy) return;
if (father[fx] < father[fy]) father[fy] = fx;
else {
if (father[fx] == father[fy]) father[fy]--;
father[fx] = fy;
}
}
struct cmp
{
bool operator()(Edge a, Edge b)
{
return a.w <b.w;
}
};
bool dmp(Edge a, Edge b)
{
return a.w <b.w;
}
priority_queue< Edge, vector<Edge>, cmp> min_t;
void KRU()
{
for (int i = 1; i <= m; i++) MAKE_SET(i);
sort(edge, edge + m, dmp);
for (int i = 0, j = 0; i < m; i++)
{
int v = edge[i].to;
int u = edge[i].u;
if (FIND(v) != FIND(u))
{
UNION(v, u);
min_t.push(edge[i]);
}
if (FIND(1)==FIND(n)) break;
}
}
int main()
{
cin >> n >> m;
int u, v, w = 0;
init();//初始化
for (int i = 1; i <= m; i++)//输入m条边
{
cin >> u >> v>>w;
add_edge(u, v, w);
//add_edge(v, u, w);
}
KRU();
if(!min_t.empty())cout << min_t.top().w;
else cout<<"0";
return 0;
}
7-4 数据结构设计I (100 分)
小唐正在学习数据结构。他尝试应用数据结构理论处理数据。最近,他接到一个任务,要求维护一个动态数据表,并支持如下操作:
插入操作(I):从表的一端插入一个整数。
删除操作(D):从表的另一端删除一个整数。
取反操作(R):把当前表中的所有整数都变成相反数。
取最大值操作(M):取当前表中的最大值。
如何高效实现这个动态数据结构呢?
输入格式
第1行,包含1个整数M,代表操作的个数, 2≤M≤1000000。
第2到M+1行,每行包含1个操作。每个操作以一个字符开头,可以是I、D、R、M。如果是I操作,格式如下:I x, x代表插入的整数,-10000000≤x≤10000000。 。
输出格式
若干行,每行1个整数,对应M操作的返回值。如果M和D操作时队列为空,忽略对应操作。
输入样例
6
I 6
R
I 2
M
D
M
输出样例
2
2
思路:
keypoint: 对于所有数字的反转的处理,引入一个标记,将所有的数按照标记存入两个数组,一个为当前状态为+时,另一个为当前状态为-时。
有两种基本思路:
1.单调队列:对整体区间求最值满足单调队列的使用。
2.使用两个单调队列,一种近似单调队列的处理方法。
法2代码
#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
using namespace std;
long long zhen[10000005], fu[10000005];
int flag = 1;
struct cmp {
bool operator()(int a, int b)
{
return zhen[a] < zhen[b];
}
};
struct dmp {
bool operator()(int a, int b)
{
return fu[a] < fu[b];
}
};
priority_queue<int , vector<int>, cmp> bq;
priority_queue<int, vector<int>, dmp> sq;
int main()
{
int num, n, sign = 0, l = 0, e = 0;
char ope;
cin >> n;
for (int i = 0; i < n; i++)
{
getchar();
scanf("%c",&ope);
if (ope == 'I')
{
scanf("%d", &num);
zhen[e] = flag * num;
fu[e] = -flag * num;
sq.push(e);
bq.push(e);
e++;
}
else if (ope == 'D')
{
if (l < e) l++;
}
else if (ope == 'R')
{
flag = -flag;
}
else if (ope == 'M')
{
if (flag == 1)
{
while (!bq.empty()&&bq.top() < l) bq.pop();
if(!bq.empty()) printf("%d\n", zhen[bq.top()]);
}
else
{
while (!sq.empty()&&sq.top() < l) sq.pop();
if(!sq.empty()) printf("%d\n", fu[sq.top()]);
}
}
}
}