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
思路:高精度加法正常是要逆序存储,因为这样会方便进位操作,但是我在考试的时候没有这样做(忘了这件事了),我就每次产生进位就进行一次 if(a[0]!='0') strcpy(a+1,a); 操作,向后移动一位,这题时间要求不是很严格,这样写可以通过。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
char a[1000010],b[110];
int n;
int main()
{
cin>>n;
n--;
scanf("%s",a+1);
while(n--)
{
scanf("%s",b+1);
int lena=strlen(a+1);
int lenb=strlen(b+1);
int len=max(lena,lenb);
char cc=0;
while(len>0)
{
if(lena>0&&lenb>0) a[len]=a[lena]-'0'+b[lenb]+cc;
else if(lena<=0&&lenb>0) a[len]=b[lenb]+cc;
else if(lena>0&&lenb<=0) a[len]=a[lena]+cc;
if(a[len]>'9') {a[len]-=10;cc=1;}
else cc=0;
lena--;len--;lenb--;
}
a[0]=cc+'0';
if(a[0]!='0') strcpy(a+1,a);
}
printf("%s",a+1);
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
思路:这道题的做法比较多,我当时是把二叉树每个节点的指针域都指向自己的父亲节点,查询时不断循环找根节点并保存距离。要注意的是可能一个节点在向上寻找的过程中找到了另一个节点,这时循环应该结束。另外,如果要查询的节点可能有根节点,而向上和向下的距离是不等的,应该加上一个特判,但其实这道题的测试样例并没有出现这种情况。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
int n,count1,count2,countt;
int pnode[100001];
int main()
{
cin>>n;
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
pnode[y]=x;
}
scanf("%d%d",&x,&y);
if(x==1||y==1)
{
if(x==1)
{
while(y!=1){
y=pnode[y];
count1++;
}
cout<<count1*2;
exit(0);
}
if(y==1)
{
while(x!=1){
x=pnode[x];
count1++;
}
cout<<count1*2;
exit(0);
}
}
while(y!=1&&y!=x){
y=pnode[y];
count1++;
}
if(y==x)
{
cout<<count1*2;
exit(0);
}
while(x!=1&&y!=x)
{
x=pnode[x];
count2++;
}
if(y==x&&x!=1)
{
cout<<count2*3;
exit(0);
}
countt=count1*2+count2*3;
cout<<countt;
return 0;
}
还有一种能想到的方法就是最短路的方法,在读入时存两个节点的距离,父亲到儿子存2,儿子到父亲存3;然后用dijkstra、SPFA等方法跑一个最短路即可。
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
思路:这道题很容易看出来是最小生成树的思想,采用Kruskal方法,不同的是这道题需要把循环结束条件改为father[n]==father[1],另外虽然题目里说只有n个施工队,但是当father[n]==father[1]时,施工队是一定够用的(可以认为只有进行Union操作的道路才会进行施工,这样到循环结束,最多有n-1个施工队修了路)
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
int father[100001],m,n;
struct Node
{
int x,y;
ll cost;
bool operator<(const Node& b)const
{
return cost < b.cost;
}
}node[200011];
int Find(int v)
{
if(father[v]==v) return v;
return father[v]=Find(father[v]);
}
void Union(int x,int y)
{
int a=Find(x);
int b=Find(y);
if(a!=b) father[a]=b;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) father[i]=i;
int x,y;
ll t;
for(int i=1;i<=m;i++)
{
scanf("%d%d%lld",&x,&y,&t);
node[i].x=x;
node[i].y=y;
node[i].cost=t;
}
sort(node+1,node+m+1);
ll minn=0;
for(int i=1;;i++)
{
if(Find(node[i].x)!=Find(node[i].y))
{
Union(node[i].x,node[i].y);
minn=node[i].cost;
}
if (Find(1) == Find(n))break;
}
cout<<minn;
system("PAUSE");
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
思路:首先可以使用STL里面的multiset,不仅可以对数据进行排序,而且允许重复元素的存在。
不用multiset还可以使用单调队列的方法,首先声明一个数组模拟队列,用f和r来保存当前剩余元素的开始下标和结束下标。另外声明两个deque保存递增、递减两个单调队列。读入元素的时候,如果标记bj==1,就把这个元素本身存入数组,把下标存入两个单调队列,如果bj==-1,就把这个元素的相反数存入数组,把下标存入单调队列。删除操作:如果单调队列的头部小于f就弹出。 取最大元素:如果bj==1,就输出递减的单调队列的头部,否则输出递增的单调队列的头部的相反数。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
typedef long long ll;
int m;
int f,r;
int bj=1;
int num[1000001];
deque<int>dq1,dq2; //1↑ ,2↓
int main()
{
cin>>m;
while(m--)
{
char c[2];
scanf("%s",c);
if(c[0]=='I')
{
r++;
scanf("%d",&num[r]);
if(bj==-1) num[r]=-num[r];
while(!dq1.empty()&&num[dq1.back()]>=num[r]) dq1.pop_back();
while(!dq2.empty()&&num[dq2.back()]<=num[r]) dq2.pop_back();
dq1.push_back(r);dq2.push_back(r);
}
else if(c[0]=='D')
{
if(f<r)
{
f++;
while(!dq1.empty()&&dq1.front()<=f) dq1.pop_front();
while(!dq2.empty()&&dq2.front()<=f) dq2.pop_front();
}
}
else if(c[0]=='M')
{
if(f<r)
{
if(bj==1) printf("%d\n",num[dq2.front()]);
else printf("%d\n",-num[dq1.front()]);
}
}
else if(c[0]=='R')
{
bj=-bj;
}
}
return 0;
}