2014年北邮网研机试
文章目录
- Problem A. 分数加法
- 题目描述
- 输入格式
- 输出格式
- 输入样例
- 输出样例
- AC代码
- 使用gcd化为最简分数
- 判断ab是否相等,绕过gcd直接化简
- 知识点补充:gcd
- Problem B. 最小堆
- 题目描述
- 输入格式
- 输出格式
- 输入样例
- 输出样例
- AC代码
- 建立二叉树递归判断法
- 并查集法
- Problem C. 进程管理
- 题目描述
- 输入格式
- 输出格式
- 输入样例
- 输出样例
- AC代码
- 双亲表示法
- Problem D. 网络传输
- 题目描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 样例说明
- AC代码
- 邻接表+dijkstra(无堆优化)+排序树dfs剪枝
- 邻接表+dijkstra(堆优化)+排序树dfs剪枝
- TLE代码
Problem A. 分数加法
https://vpn.bupt.edu.cn/http/10.105.242.80/problem/p/266/
题目描述
求2-a + 2-b,其中a和b均为正整数,结果请用最简分数表示。
输入格式
第一行为测试数据的组数T(1<=T<=400)。请注意,任意两组测试数据之间是相互独立的。
每组测试数据一行,包含两个整数a和b(2<=a,b<=20)。
输出格式
对于每组测试数据,在一行内输出结果,分子和分母用“/”隔开。
输入样例
2
2 4
3 2
输出样例
5/16
3/8
AC代码
使用gcd化为最简分数
#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 100
#define INF 1000000
#define bug(x) cout<<#x<<"="<<x<<endl;using namespace std;
typedef long long ll;
const double pi=acos(-1);void FractionAdd(int a_,int b_,ll & u,ll & v){//ans=u/vint a=min(a_,b_);int b=max(a_,b_);u=v=(ll)1;v<<=b;u<<=(b-a);u++;
}int main()
{freopen("./in","r",stdin);int T,a,b;ll u,v;scanf("%d",&T);while(T--){scanf("%d%d",&a,&b);FractionAdd(a,b,u,v);ll d=__gcd(u,v);printf("%lld/%lld\n",u/d,v/d);}return 0;
}
判断ab是否相等,绕过gcd直接化简
此方法需要对一些特例进行特判,相比较上法较为复杂。不过能避免一次位运算,在某些样例中能避免溢出。
#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 100
#define INF 1000000
#define bug(x) cout<<#x<<"="<<x<<endl;using namespace std;
typedef long long ll;
const double pi=acos(-1);void FractionAdd(int a_,int b_,ll & u,ll & v){//ans=u/vif(a_-b_){int a=min(a_,b_);int b=max(a_,b_);u=v=(ll)1;v<<=b;u<<=(b-a);u++;}else{ //a=bu=v=1;v<<=(a_-1);}}int main()
{// freopen("./in","r",stdin);int T,a,b;ll u,v;scanf("%d",&T);while(T--){scanf("%d%d",&a,&b);if(!a&&!b){ //a=b=0 特例puts("2/1");continue;}FractionAdd(a,b,u,v);printf("%lld/%lld\n",u,v);}return 0;
}
知识点补充:gcd
int gcd(int a,int b){while( b != 0){int t = a % b;a = b;b = t;}return a;
}
Problem B. 最小堆
https://vpn.bupt.edu.cn/http/10.105.242.80/problem/p/267/
题目描述
给定一棵带权二叉树,请判断它是不是一个最小堆。
一棵二叉树是一个最小堆,当且仅当对于树上任意一个节点,它的权值都小于或等于以它为根的子树中的所有权值。
输入格式
输入数据第一行是一个整数T(1<=T<=100),表示测试数据的组数。
对于每组测试数据:
第一行是一个整数N(1<=N<=100),表示树的节点个数。
接下来一行包含N个正整数,第i个整数valuei(1<=valuei<=1000)表示编号i的点的权值。
接下来N-1行,每行两个整数u和v(1<=u,v<=N, u!=v),表示节点u是节点v的父节点。
测试数据保证给定的一定是一棵二叉树,并且节点1是树的根结点。
输出格式
对于每组测试数据,如果给定的树是一个最小堆则输出Yes,否则输出No。
输入样例
3
1
10
3
10 5 3
1 2
1 3
5
1 2 3 4 5
1 3
1 2
2 4
2 5
输出样例
Yes
No
Yes
AC代码
建立二叉树递归判断法
#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 100
#define INF 1000000
#define bug(x) cout<<#x<<"="<<x<<endl;using namespace std;
typedef long long ll;
const double pi=acos(-1);int w[110];
int in[110];
typedef struct Node{int i;vector<int> c;
}Node;
Node tree[110];bool judge(int r){FF(i,tree[r].c.size()){int c=tree[r].c[i];if(w[r]>w[c] || judge(c)==0)return 0;}return 1;
}int main()
{// freopen("./in","r",stdin);int T,N,a,b;scanf("%d",&T);memset(in,0,sizeof in);while(T--){scanf("%d",&N);F(i,N){scanf("%d",&w[i]);tree[i].c.clear();//不初始化就wa}F(i,N-1){scanf("%d%d",&a,&b);tree[a].c.push_back(b);in[b]++;}int root=1;puts(judge(root)?"Yes":"No");}return 0;
}
并查集法
reference:https://blog.csdn.net/u012963208/article/details/62044980
不过感觉法2的时间复杂度比法1还高…
Problem C. 进程管理
https://vpn.bupt.edu.cn/http/10.105.242.80/problem/p/268/
题目描述
在操作系统中,进程管理是非常重要的工作,每个进程都有唯一的进程标识(PID)。每个进程都可以启动子进程,此时我们称它为其子进程的父进程,除了PID为0的进程之外,每个进程有且只有一个父进程,在这个任务中,你需要实时维护操作系统运行中的三个基本操作:
FORK PID1 PID2
:标识为PID1的进程启动了一个标识为PID2的子进程。KILL PID
:结束标识为PID的进程。请注意,与此同时所有PID的子进程也将同时结束。如果PID是不存在或已经结束的进程,则不做任何操作。QUERY PID
:查询标识为PID的进程是否仍然存在。
在初始状态下,系统只开启了PID为0的进程,并且在任何情况下该进程不会结束。
输入格式
输入的第一行是一个整数T(T<=50),表示输入的数据组数。
每组测试数据的第一行是一个整数N(1<=N<=100),表示操作的数量。
每下来N行,每行按照上面的描述给出每个操作,输入保证所有的进程的PID都不相同,且一个进程结束后不会被重新启动,所有PID都是[1,100]之间的整数。
输出格式
对于每次QUERY
查询,如果进程存在,输出Yes
,不存在则输出No
输入样例
2
5
FORK 0 1
QUERY 1
KILL 1
QUERY 1
QUERY 2
1
QUERY 0
输出样例
Yes
No
No
Yes
AC代码
双亲表示法
想写孩子双亲表示的,一直wa,无解。
此法比较暴力,待优化
#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 110
#define INF 1000000
#define bug(x) cout<<#x<<"="<<x<<endl;using namespace std;
typedef long long ll;
const double pi=acos(-1);int fa[LEN];void kill(int u){fa[u]=-1;FF(i,LEN)if(fa[i]==u)kill(i);
}int main()
{// freopen("./in","r",stdin);int T,N;int a,b;char op[10];scanf("%d",&T);while(T--){scanf("%d",&N);memset(fa,-1,sizeof fa);fa[0]=0;while(N--){scanf("%s%d",op,&a);switch(op[0]){case 'F':scanf("%d",&b);fa[b]=a;break;case 'K':kill(a);break;case 'Q':puts(fa[a]>=0?"Yes":"No");break;}}}return 0;
}
Problem D. 网络传输
https://vpn.bupt.edu.cn/http/10.105.242.80/problem/p/269/
题目描述
网络的高效互联与智能传输是提升海量用户服务请求映射效率的重要措施。在这个任务中,你要用最少的传输时间,将特定的数据源发送到指定的网络节点中。
我们给定的网络一共包含N个节点(从1到N编号),其中节点1为数据源。网络中有M条无向边(u,v,w),表示一条传输线连接节点u和节点v,且数据通过这条传输线的平均时间为w。由于传送机制的限制,当一个节点接收到数据之后,它只能选择与它互连的一个节点,并将数据转发到该节点。节点1在初始化时只会发送一次数据,但在传输过程中它可以作为转发节点。
网络中有k个目标节点,你需要计算出该数据从节点1传送到所有K个节点所需要的最短时间。注意目标节点可以按任意顺序进行传送,数据也可以多次经过同一节点。
输入格式
输入数据第一行是一个整数T(T<=5),表示测试数据的组数。
对于每组测试数据:
第一行是三个正整数N,M,K(2<=N<=1000,1<=M<=N(N-1)/2,K<=10),分别表示节点数,边数和目标节点数。
接下来M行,每行三个整数u,v,w(1<=u,v<=N, 0<=w<=1000,u!=v)。如上所述给出每条传输线。任意两个网络节点之间最多只会有一条边相连。
最后一行是K个整数,给出所有的目标节点的编号,所有目标节点的编号都在2到N之间。
输出格式
对于每组测试数据,输出数据传送到所有K个目标节点的最短时间。
样例输入
2
3 2 2
1 3 1
1 2 3
2 3
6 6 4
1 5 1
5 6 2
2 1 20
2 3 5
3 4 5
6 3 1
2 3 4 6
样例输出
5
19
样例说明
在第一组样例中,最短路线是:1->3->1->2
在第二组样例中,最短路线是:1->5->6->3->2->3->4,或者1->5->6->3->4->3->2
思路:https://blog.csdn.net/u012963208/article/details/64457190?utm_source=blogxgwz4
AC代码
邻接表+dijkstra(无堆优化)+排序树dfs剪枝
时间:900ms
#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 110
#define INF 2000
#define bug(x) cout<<#x<<"="<<x<<endl;using namespace std;
typedef long long ll;
const double pi=acos(-1);#define VN 1100
#define EN 31000int via[VN];//途经点
int dist[VN][VN];//dist[0]
int vis[VN];
int N,M,K;
typedef struct edge{int to,w;edge(int to,int w):to(to),w(w){}
}edge;
vector<edge> g[VN];int dijkstra(int s){memset(vis,0,sizeof vis);fill(dist[s],dist[s]+N+1,INF);//无N+1导致wadist[s][s]=0;//优先队列初始化while(1){ //优先队列非空int u=-1,min_d=INF;F(i,N){if(vis[i]==0 && dist[s][i]<min_d){u=i;min_d=dist[s][i];}}if(u==-1) break;//找到最小u点vis[u]=1; //找到最近点,加入S集for(int i=0;i<g[u].size();i++){ //链式前向星遍历int to=g[u][i].to; //链式前向星: u 的后继点 toint w=g[u][i].w; //链式前向星: u -> to 边权if(!vis[to]){ //松弛if(dist[s][to] > dist[s][u]+w) { //s->to > s->u->todist[s][to] = dist[s][u] + w;}}}}
}int sum=0,ans=0x7FFFFFFF;void solve(int t){//对via进行全排列if(t>K){ans=min(sum,ans);}else{for(int i=t;i<=K;i++){swap(via[t],via[i]);sum+=dist[via[t-1]][via[t]];if(sum<ans) solve(t+1);sum-=dist[via[t-1]][via[t]];swap(via[t],via[i]);}}
}int main()
{// freopen("./in","r",stdin);int T;int u,v,w;scanf("%d",&T);while(T--){scanf("%d%d%d",&N,&M,&K);F(i,N)g[i].clear();while(M--){scanf("%d%d%d",&u,&v,&w);g[u].push_back(edge(v,w));g[v].push_back(edge(u,w));}via[0]=1;dijkstra(1);F(i,K){scanf("%d",via+i);dijkstra(via[i]);//仅仅需要计算途经点到其余点的最短距离}sum=0,ans=0x7FFFFFFF;solve(1);printf("%d\n",ans);}return 0;
}
邻接表+dijkstra(堆优化)+排序树dfs剪枝
时间:800ms
需要注意的是,对于小数据量,堆优化起得作用不大。本题大数据量的确发挥了作用,加速了100ms。
非常值得注意的是,在松弛判断语句中:
红框内必须使用>=
,否则WA
#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 110
#define INF 2000
#define bug(x) cout<<#x<<"="<<x<<endl;using namespace std;
typedef long long ll;
const double pi=acos(-1);#define VN 1100
#define EN 31000int via[VN];//途经点
int dist[VN][VN];//dist[0]
int vis[VN];
int N,M,K;
typedef struct edge{int to,w;edge(int to,int w):to(to),w(w){}
}edge;
vector<edge> g[VN];//---------------------堆优化----------------------------
int cur;
struct cmp{bool operator () (int a,int b){return dist[cur][a]>dist[cur][b];}
};
priority_queue<int,vector<int>,cmp> pq;
//---------------------堆优化----------------------------int dijkstra(int s){cur=s;//用于优先队列比较memset(vis,0,sizeof vis);fill(dist[s],dist[s]+N+1,INF);//无N+1导致wadist[s][s]=0;//优先队列初始化
// pq=priority_queue<int,vector<int>,cmp>();//定义粘贴过来强行初始化。也可以pop到空初始化while(!pq.empty())pq.pop();pq.push(s);//dijkstra主循环while(!pq.empty()){ //优先队列非空int u=pq.top();pq.pop();if(vis[u]) continue;//排除已访问点vis[u]=1; //找到最近点,加入S集for(int i=0;i<g[u].size();i++){ //链式前向星遍历int to=g[u][i].to; //链式前向星: u 的后继点 toint w=g[u][i].w; //链式前向星: u -> to 边权if(!vis[to]){ //松弛if(dist[s][to] >= dist[s][u]+w) { //s->to > s->u->todist[s][to] = dist[s][u] + w;pq.push(to); //没有就wa}}}}
}int sum=0,ans=0x7FFFFFFF;void solve(int t){//对via进行全排列if(t>K){ans=min(sum,ans);}else{for(int i=t;i<=K;i++){swap(via[t],via[i]);sum+=dist[via[t-1]][via[t]];if(sum<ans) solve(t+1);sum-=dist[via[t-1]][via[t]];swap(via[t],via[i]);}}
}int main()
{// freopen("./in","r",stdin);int T;int u,v,w;scanf("%d",&T);while(T--){scanf("%d%d%d",&N,&M,&K);F(i,N)g[i].clear();while(M--){scanf("%d%d%d",&u,&v,&w);g[u].push_back(edge(v,w));g[v].push_back(edge(u,w));}via[0]=1;dijkstra(1);F(i,K){scanf("%d",via+i);dijkstra(via[i]);//仅仅需要计算途经点到其余点的最短距离}sum=0,ans=0x7FFFFFFF;solve(1);printf("%d\n",ans);}return 0;
}
TLE代码
另外,我最开始是用链式前向星写得本题。但是一直都是TLE。如果智慧的读者您发现了我代码中的错误,麻烦您留言告诉我,谢谢!
#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 110
#define INF 2000
#define bug(x) cout<<#x<<"="<<x<<endl;using namespace std;
typedef long long ll;
const double pi=acos(-1);#define VN 1100
#define EN 31000int via[VN];//途经点
int dist[VN][VN];//dist[0]
int vis[VN];
int cur;
int N,M,K;//---------------------链式前向星----------------------------
int head[VN]; //记录源点u在mp中第一个地址i=head[u] 调用完之后就可以用mp[i]访问边表mp
int cnt=0; //边表下标,随着数据的录入而扩张
struct edge{ //边int to,next,w;
};
edge mp[EN*2]; //边表
void add(int u,int v,int w){ //增加边mp[cnt].to=v;mp[cnt].w=w;mp[cnt].next=head[u]; //指向源点u所构成的静态链表的头结点。如果是首次构造链,head[u]=-1 ,相当于NULLhead[u]=cnt++; //更新当前地址
}
void init_mp(){memset(head,-1,sizeof head);cnt=0;
}
//---------------------链式前向星----------------------------
//---------------------堆优化----------------------------
struct cmp{bool operator () (int a,int b){return dist[cur][a]>dist[cur][b];}
};
priority_queue<int,vector<int>,cmp> pq;
//---------------------堆优化----------------------------void dijkstra(int s){//dist[2]cur=s;memset(vis,0,sizeof vis);fill(dist[s],dist[s]+N+1,INF);//无N+1导致wadist[s][s]=0;while(!pq.empty())pq.pop();pq.push(s); //优先队列初始化while(!pq.empty()){ //优先队列非空int u=pq.top(); //找到最小u点pq.pop();if(vis[u]) continue;//找到最小u点vis[u]=1; //找到最近点,加入S集for(int i=head[u];~i;i=mp[i].next){ //链式前向星遍历int to=mp[i].to; //链式前向星: u 的后继点 toint w=mp[i].w; //链式前向星: u -> to 边权if(!vis[to]){ //松弛if(dist[s][to] > dist[s][u]+w) { //s->to > s->u->todist[s][to] = dist[s][u] + w;pq.push(to);//无此,wa}}}}
}int calc_w(){int res=0;for(int i=1;i<=K;i++){res+=dist[via[i-1]][via[i]];}return res;
}void solve(int t){//对via进行全排列}int main()
{// freopen("./in","r",stdin);int T;int u,v,w;scanf("%d",&T);while(T--){scanf("%d%d%d",&N,&M,&K);init_mp(); //对于每个样例,必须要重新初始化一次前向星while(M--){scanf("%d%d%d",&u,&v,&w);add(u,v,w);add(v,u,w);}via[0]=1;dijkstra(1);F(i,K){scanf("%d",via+i);dijkstra(via[i]);//仅仅需要计算途经点到其余点的最短距离}int ans=0x7FFFFFFF;//dist[3]do{ans=min(ans,calc_w());ans=ans;}while(next_permutation(via+1,via+K+1));//最多10个K,计算量为10!=3628800printf("%d\n",ans);}return 0;
}
2014年北邮网研机试相关推荐
- 2014北邮网研机试
注意:所有代码均是根据题目描述进行了本地测试,没有在北邮oj上测试,不保证一定能AC. 点击链接查看历年机试题目汇总. A分数加法 题目描述 求2^(-a)+2^(-b),其中a和b均为正整数,结果请 ...
- 2013北邮网研机试
注意:所有代码均是根据题目描述进行了本地测试,没有在北邮oj上测试,不保证一定能AC. 点击链接查看历年机试题目汇总. A最值问题 题目描述 给出N个数,求出这N个数中最大值和次大值.注意这里的次大值 ...
- 2019北邮网研机试
注意:所有代码均是根据题目描述进行了本地测试,没有在北邮oj上测试,不保证一定能AC. 点击链接查看历年机试题目汇总. A牙膏问题 题目描述 4只牙膏比较价格,返回最便宜的牙膏. 输入: 第一行输入T ...
- 2018北邮网研机试
注意:所有代码均是根据题目描述进行了本地测试,没有在北邮oj上测试,不保证一定能AC. 点击链接查看历年机试题目汇总. A商品总价格 题目描述 类似超市结账,计算购买的商品的总价格. 输入: 第一行为 ...
- 2012北邮网研机试
注意:所有代码均是根据题目描述进行了本地测试,没有在北邮oj上测试,不保证一定能AC. 点击链接查看历年机试题目汇总. A打印字符串 题目描述 老师有一个问题想考考mabo,但是mabo不会,所以想请 ...
- 2018北邮网研机试真题(大佬们的回忆版)
Problem 1 题目: 类似超市结账,计算购买的商品的总价格. 输入: 第一行为测试数据组数T(0< T <= 10) 每组数据第一行为购买商品的种类n,接下来n行,每行两个数据,第一 ...
- 2015北邮网研机试
Problem A 输入: 3 3 5 8 输出: 1 2 4 因为n小于等于30,而30以内的质数一共就10个.所以直接写出来比较大小就好 #include<stdio.h> int m ...
- 2018北邮网研机试-A
Problem A 类似超市结账,计算购买的商品的总价格. 输入: 第一行为测试数据组数T(0<T<=10) 每组数据第一行为购买商品的种类n,接下来n行,每行两个数据,第一个为商品价格, ...
- 2018北邮网研机试-D 的更好解法
https://blog.csdn.net/birdreamer/article/details/79749068 上面是原题超链: 原博D题的做法有点太浪费空间 #include <iostr ...
最新文章
- SharePoint Server 2016 部署安装(三)—— 安装SharePoint Server
- 版本更新带来的缓存问题_浏览器缓存原理总结
- java工程师的终极书单_Java 9 –终极功能列表
- 当年,兔子学姐靠这个面试小抄拿了个22k
- 获取css selector,selenium的css selector元素获取方式
- hdu 3333 Turing Tree 求区间内不同数的和——线段树解法
- Go 语言为Fibonacci函数实现Read方法
- 基于ftp4j的FTP客户端工具
- HeadFirstJava——2_类与对象
- Java 如何生成 UUID
- jrtplib linux编译,linux下jrtplib-3.9.1编译与安装.txt
- 商家如何制作外卖小程序并且对接同城外卖配送平台?
- 芒格推荐书单(完全版32本)
- 弱水三千的由来(转)
- iPhone删除的照片能恢复吗?苹果手机照片怎么恢复
- Nginx配置Https 443 端口
- webView系列(五)----历史记录
- python中成语接龙游戏_Python实现成语接龙
- OPENFILER构建软iSCSI multipath实现多路径聚合(一)
- C语言通讯录系统程序设计