本博客根据相关的例题,完成相应的算法笔记
级 数 求 和
Description
已知 Sn = 1 + 1/2 + 1/3 + ... + 1/n. 显然对于一个任意整数K,当n足够大的时候,Sn 大于 K。
现给出一个整数 K(1≤K≤20), 要求计算出一个最小的 n,使得 Sn > K.
Input
一个正整数 K
Output
一个正整数 N
Sample Input 1
1
Sample Output 1
2
#include <bits/stdc++.h>
using namespace std;
int main() {
int k,n=0;
scanf("%d",&k);
for(double Sn=0;Sn<=k;++n,Sn+=1.0/n);
printf("%d",n);
return 0;
}
这题比较简单,没有解释
女 装 Plan
zjj非常rich,但是最近手头只有两种面值的金币,两种面值均为正整数且彼此互素。为了让实验室成员都有女装穿,zjj准备了 无数 的金币。可是在不找零的情况下,有些女装是无法准确支付的,现在zjj想知道,在无法准确支付的女装中,最贵的价值多少金币
注意:输入数据保证存在无法准确支付的女装
Input
两个正整数 a 和 b,它们之间用一个空格隔开,表示zjj手中金币的面值
ouput
一个正整数 N,表示zjj在不找零的情况下无法准确支付的最贵的女装价值
sample input 3 7
sample ouput 11
注意
//我在博客中曾经写过关于 扩张欧几里得算法
//定理1:给定两个非零整数 a和b,求一组整数解(x,y)
//使得ax+by=gcd(a,b)成立,其中gcd(a,b)表示a和b的最大公约数
//定理2:
//对于正整数p , q满足gcd(p, q) = 1,
//我们有px + qy = n 不能实现的最大正整数n 为pq - p - q .
//两者的不同点在于定理1 p,q未知,求存在解x,y
//定理2:p,q已经知道,求px+qy不能实现的最大值
//这个题目中给的数据都是互质的,如果不是互质的那么结果为1
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
long long a,b;
cin>>a>>b;
long long ans=a*b-a-b;
cout<<ans;
return 0;
}
手办迁居
作为cdd的mx打算把已经装箱的手办全都带回家,并且按照单推程度分成了不同的堆,现在mx想把各堆的手办箱子都合成一堆。
每一次合并,mx可以把两堆手办合并到一起,消耗的体力等于两堆手办的重量之和,可以看出,经过n-1次合并后就变成一堆了。mx在合并手办时消耗的总体力等于每次所耗体力之和。
因为mx实在太弱了,所以想尽可能节省体力,假定每箱手办重量都为 1 ,并且已知堆的数量和每堆手办的数量。请你帮mx算算他最少只需要花费多少体力
input
共两行
第一行是一个整数 n,表示手办的堆数
第二行包括 n 个整数,用空格分隔,第 i 个整数 ai 是第 i 堆手办的数目
1<ai<20000
output
一个整数,即最小的体力耗费,数据保证这个值小于2^31
sample input
3
1 2 9
sample output
15
#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
using namespace std;
int main()
{
priority_queue<long long , vector<long long > , greater<long long > > q;
//优先队列默认事less<int>是降序,所以使用greater<int>作为升序
int m;
long long num;
long long sum;
cin>>m;
sum = 0;
while(m--)
{
cin>>num;
q.push (num);
}
while(q.size()!=1)//用于记录优先队列的长度,当只剩最后一个数的时候就停止
{
num = q.top();
q.pop ();
num += q.top ();
q.pop ();
q.push (num);
sum += num;
}
cout<<sum << endl;
return 0;
}
社恐的朋友圈
YouChat最近开启了一个新功能,可以让朋友的朋友成为你的朋友,但是有社交障碍的mx很难判断他跟谁有朋友关系,他给了你一个朋友关系图,请你帮他看看任意两个人是不是朋友
例如:x和y是朋友,y和z是朋友,那么x和z也是朋友;如果x,y是朋友,那么x的朋友都是y的朋友,y的朋友都是x的朋友
input
第一行包含3个整数 n,m,k 分别表示有 n 个人,m 个朋友关系,询问 k 对朋友关系
接下来 m 行:每行两个数 Mi,Mj 表示 Mi 和 Mj 具有朋友关系
接下来 k 行:每行两个数 Ki,Kj 询问 Ki 和 Kj 是否有朋友关系
output
接下来 k 行:每行两个数 Ki,Kj 询问 Ki 和 Kj 是否有朋友关系
sample input
6 5 3
1 2
1 5
3 4
5 2
1 3
1 4
2 3
5 6
sample output
Yes
Yes
No
这题的思想是借助并查集的方式解决问题
并查集有相应的模块
并查集的应用十分广泛,包括一些算法,当应用上并查集的时候,也会更容易实现。下面总结下并查集的相关内容
个人的理解是:并查集就是对集合三种常用操作的再一次抽象。分别是集合的合并(Union)、元素的搜索(Find)和对集合的分解。因为这3中操作非常常用并且又不囿于集合,所以就把这一组操作抽象成一个独立的数据结构。
标准定义
int unionsearch(int root) //查找根结点
{
int son, tmp;
son = root;
while(root != pre[root]) //我的上级不是掌门
root = pre[root];
while(son != root) //我就找他的上级,直到掌门出现
{
tmp = pre[son];
pre[son] = root;
son = tmp;
}
return root; //掌门驾到~~
}
下面是题目代码
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int mark[5005],fa[5005];
int get(int x){
if(fa[x]==x)return x;
return fa[x]=get(fa[x]);
}
int main(){
int n,m,p;cin>>n>>m>>p;
int a,b;
memset(mark,0,sizeof(mark));
for(int i=1;i<=n;i++)fa[i]=i;//初始化设置
while(m--){//输入m组朋友关系
cin>>a>>b;//
a=get(a);//获得a和谁是朋友关系
b=get(b);
if(a!=b){
fa[a]=b;
}
}
for(int i=1;i<=p;i++){
cin>>a>>b;
a=get(a);b=get(b);
if(a==b)mark[i]=1;
}
for(int i=1;i<=p;i++){
if(mark[i])cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
LifeCanAche
给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先
第一行包括3个正整数 N M S 分别表示树的结点的个数、询问的个数和树根结点的序号
接下来 N-1 行每行包含两个正整数 x,y 表示 x与y 之间有一条直接连接的边(数据保证可以构成树)
接下来M行每行包含2个正整数 a,b 表示询问 a和b 的最近公共祖先
题目保证,N≤10000,M≤10000
题目链接http://oj.nhjc.ac.cn/contest/5/problem/E
#include <bits/stdc++.h>
#define N 500005
#define pb push_back
using namespace std;
vector<int>que[N];
struct node
{
int next,to;
}edge[N<<2];
int head[N<<2],cnt,y,u[N],v[N],dad[N],n,m,root,fa[N],ans[N];
void add(int u,int v)
{
edge[++cnt].next=head[u];
edge[cnt].to=v;
head[u]=cnt;
}
int read()
{
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch))
{
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int find_(int x) {return x==fa[x]?x:fa[x]=find_(fa[x]);}
void dfs(int x)
{
fa[x]=x;
for(int i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if(dad[x]!=v)
{
dad[v]=x;
dfs(v);
}
}
for(int i=0;i<que[x].size();i++)if(dad[y=x^u[que[x][i]]^v[que[x][i]]]) ans[que[x][i]]=find_(y);
fa[x]=dad[x];
}
int main()
{
n=read();
m=read();
root=read();
int x,y;
for(int i=1;i<n;i++)
{
x=read();y=read();
add(x,y);
add(y,x);
}
for(int i=1;i<=m;i++)
{
u[i]=read();v[i]=read();
que[u[i]].pb(i);
que[v[i]].pb(i);
}
dfs(root);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}