upc 个人训练赛第四场:黑匣子+选地址(优先队列+弗洛伊德最短路)

本文主要是介绍upc 个人训练赛第四场:黑匣子+选地址(优先队列+弗洛伊德最短路),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题 A: 13号星期几

题目描述
请编程统计:从1900年1月1日(当天是星期一)开始经过的n年当中,每个月的13号这一天是星期一、星期二、星期三、……、星期日的次数分别是多少?
输入
共一行,一个整数n (1≤n≤400)。
输出
仅一行, 有7个整数(依次是星期一、星期二、星期三、……、星期日的次数),各数间以空格相隔,行尾不能有多余的空格。
样例输入 Copy
1
样例输出 Copy
1 3 1 2 2 2 1

思路:
定义一个x,让他从1号开始循环,如果加一大于当前月份的值,就结束当前月份的循环,循环的同时判断对7取余的值,相应的余数开一个数组然后++即可

int n,x,t;
int a[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int vis[10];//记录周一到周天是13号的次数
int judge(int y)
{if((y%4 == 0 && y%100 != 0) || (y%400 == 0))return 1;else    return 0;
}int main()
{cin >> n;for(int i=1900;i<1900+n;i++){if(judge(i))    a[2]++;else    a[2] = 28;for(int j=1;j<=12;j++)//月份{x = 0;while(1){if(x+1 > a[j])   break;x++;t = (t+1)%8;if(t == 0)  t = 1;if(x == 13) vis[t]++;}}}for(int i=1;i<=7;i++)printf("%d ",vis[i]);printf("\n");return 0;
}

问题 B: 高兴的小明

题目描述
今天,小明很高兴,因为国庆放假了,又恰逢是自己的生日。为了庆祝节日,小明与邻居的小伙伴共n个人相约一起放花炮。他们先同时放响了第一个花炮,随后n个人分别以A1、A2、A3、……An秒的间隔继续放花炮,到最后每人都放了b个花炮(包括第一个)。问:总共可听到多少声花炮响?
输入
共三行,第一行仅一个整数n(n<=10),第二行是A1、A2、A3、……An共n个整数(每个数<=100,各数间以空格相隔),第三行只有一个整数b(b<=100)。
输出
仅一行,一个整数(听到的花炮响声数),行尾不能有多余的空格。
样例输入 Copy
3
1 2 3
4
样例输出 Copy
7

思路:
首先第一个花炮是同时放的,所以只能听到一次声响,即从ans = 1开始,之后观察数据发现,每个人放花炮听到声响其实就是一个等差数列,给出的间隔就是公差,同时在同一时间放出的花炮只能听见一次声响,问题就解决了
我一开始想用数组直接记录下放花炮的时间,最后发现还需要去重,于是我就想到了另外一种办法,可以直接让放花炮的时间做数组的下标,如果能听到就标记为1,这样就不容易出错了

int n,b,ans,cnt;
int a[15],c[10005];
int main()
{cin >> n;for(int i=1;i<=n;i++)    cin >> a[i];cin >> b;for(int i=1;i<=n;i++){for(int j=1;j<=b-1;j++){c[j*a[i]] = 1;}}ans = 1;for(int i=1;i<=10000;i++){if(c[i] == 1)   ans++;}cout << ans << endl;return 0;
}

问题 C: 摘彩球

题目描述
今年是国庆60周年,学校少先队大队部举行了庆祝活动,其中有一项活动是摘彩球。大队辅导员在学校礼堂里高低不一地挂了N个彩球,请M位少先队员到礼堂里摘彩球。辅导员说:你们每人最多可以摘两个彩球,而且只许站着伸手摘,不允许借助其它工具,摘下的彩球归大家共有。由于各少先队员的身高参差不齐,怎样才能使他们摘的彩球总数最多呢?请你计算少先队员们最多能摘到多少个彩球?
输入
第一行有二个整数N 和M(N<=100,M<=20),两数间用空格隔开。
第二行有 N个整数(各数间以空格相隔),分别表示每个彩球的高度。
第三行有M个整数(各数间以空格相隔),分别表示每个少先队员伸手能达到的高度。
输出
仅一行,有一个整数,表示最多能摘到的彩球数,行尾不能有多余的空格。
样例输入 Copy
10 4
110 100 150 90 100 135 160 88 130 140
120 100 110 80
样例输出 Copy
5

思路:
这个题我先排序然后去掉了根本就够不到的彩球,然后循环比较大小,一旦彩球可以被摘下来,就把彩球的高度变为1,循环过程中不断判断ans % 2,如果为0,结束本次循环

int n,m,x,ans,cnt;
int a[105],b[25];
bool cmp(int x,int y)
{return x > y;
}int main()
{cin >> n >> m;for(int i=1;i<=n;i++)    cin >> a[i];for(int i=1;i<=m;i++)    cin >> b[i];sort(a+1,a+1+n,cmp);//降序 sort(b+1,b+1+m,cmp);for(int i=1;i<=n;i++){if(b[1] < a[i])  a[i] = 0;}//去掉根本够不到的 for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){if((b[i] >= a[j]) && (a[j] != 0)){ans++;a[j] = 0;if(ans%2 == 0)  break;}}}cout << ans << endl;return 0;
}

问题 D: 莱布尼茨三角形

题目描述
世界上著名的莱布尼茨三角形如图所示,请编程输出图中排在第n行从左边数第m个位置上的数。
在这里插入图片描述
输入
共一行,有二个整数N 和M(N<=15),两数间用空格隔开。
输出
共一行,有二个整数,两数间用“/”隔开,表示所求的分数,行尾没有多余的空格。
样例输入 Copy
7 3
样例输出 Copy
1/105

思路:
这个题我的思路是先建立起图示的三角形,然后查找就可以了,观察这个三角形,利用我高中对数组求和留下的深刻印象,我一眼就发现了,从第三列开始,每一列从第二个数开始等于它上一行前一列的数减去它前一个数,即a[i][j] = a[i-1][j-1] - a[i][j-1],同时这个三角形又是对称的,即a[i][j] = a[i][i-j+1],我们知道分子一定是1,所以每次只需要计算分母就可以了

int a[20][20];
int n,m,ans;
int jianfa(int a,int b)//求分母 
{int x,y,z;z = gcd(a,b);y = a*b/z;x = 1*(y/a)-1*(y/b);z = gcd(x,y);y = y/z;return y;
}int main()
{cin >> n >> m;for(int i=1;i<=15;i++){a[i][1] = a[i][i] = i; }for(int i=3;i<=15;i++){for(int j=2;j<=(i-1)/2+1;j++)//上取整 {a[i][j] = a[i][i-j+1] = jianfa(a[i-1][j-1],a[i][j-1]);}}for(int i=1;i<=15;i++){for(int j=1;j<=15;j++){ans = a[n][m];}}printf("1/%d",ans);return 0;
}

问题 E: 黑匣子

题目描述
Black Box是一种原始的数据库。它可以存储一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的,而i等于0。这个Black Box要处理一串命令。
命令只有两种:
ADD(x):把x元素放进Black Box;
GET:i加1,然后输出Black Box中第i小的数。
记住:第i小的数,就是Black Box里的数按从小到大的顺序排序后的第i个元素。
例如: 我们来演示一下一个有11个命令的命令串。(如下图所示)
序号 操作 i 数据库 输出
1 ADD(3) 0 3
2 GET 13 3
3 ADD(1) 11, 3
4 GET 21,3 3
5 ADD(-4) 2 -4,1, 3
6 ADD(2) 2-4,1,2,3
7 ADD(8) 2-4,1,2,3,8
8 ADD(-1000)2-1000,-4,1,2,3,8
9 GET 3 -1000,-4,1,2,3,81
10 GET 4 -1000,-4,1,2,3,8 2
11 ADD(2) 4-1000,-4,1,2,2,3,8

现在要求找出对于给定的命令串的最好的处理方法。ADD和GET命令分别最多有200000个。

现在用两个整数数组来表示命令串:
1、A(1),A(2),…A(M):一串将要被放进Black Box的元素。每个数都是绝对不超过2000000000的整数,M≤200000。例如上面的例子就是
A=(3,1,-4,2,8,-1000,2)。
2、u(1),u(2),…u(N):表示第u(j)个元素被放进了Black Box里后就出现了一个GET命令。例如上面的例子中的u=(1,2,6,6)。
输入数据不用判错。

输入
第一行,两个整数,M,N。
第二行,M个整数,表示A(1) …A(M)。
第三行,N个整数,表示u(1)…u(N)。
输出
输出Black Box根据命令串所得出的输出串,一个数字一行。
样例输入 Copy
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
样例输出 Copy
3
3
1
2
提示
对于30%的数据,M≤10000;
对于50%的数据,M≤100000
对于100%的数据,M≤200000

思路:
这个题的题意我是读了好几遍才明白的,它是说有一个堆,一开始是个空堆,同时有一个变量s = 0,现在有两种操作,ADD和GET,ADD表示元素要入队,当当前第u[i]个数入队时,GET一下,s++,并且输出当前第s小的数。由于要不停的输出第s小的数,我想了很久,发现用数组一遍遍的查找太麻烦,于是想到了今天看了很久的数据结构,发现这个规律貌似可以用优先队列来解决
用两个优先队列分别维护a[i]和u[i],将a[i]存放在大根堆中,如果大根堆的元素数量大于s时,就把大根堆的队顶元素放进小根堆,一旦满足GET的条件,只需要输出当前小根堆的队顶元素即可

int a[maxn],b[maxn],n,m;
int main()
{cin >> n >> m;for(int i=1; i<=n; i++)	scanf("%d",&a[i]);for(int i=1; i<=m; i++)	scanf("%d",&b[i]);int s = 0,k = 1;for(int i=1; i<=n; i++){q2.push(a[i]);//入队 if(q2.size() > s) q1.push(q2.top()),q2.pop();//q2的队顶元素放进q1while(b[k] == i)//遇到这个操作,相对应的迭代器s++ //输出第s小,放进q1的自动按小到大排序,每次输出队顶元素即可 {printf("%d\n",q1.top());k++;//控制循环 s++;q2.push(q1.top());//放回q2 q1.pop(); }}return 0;
}

问题 F: 选地址

题目描述
小X有很多朋友、、分布在N个城市。。
这N个城市之间,有些有直接的道路,有些是间接联通的(保证任何两个城市都可以相互到达。。)
但是、经过每条道路都是有代价的、、
于是。。
小X希望你来帮他找出一个城市,使得他的所有朋友到这个城市的代价最小。
输入
输入共2N+1行,
其中第一行为一个整数N、
第2~N+1行
每行有N个整数、表示两个城市间的代价、(0表示不直接连通)
第n+2~2
N+1行
每行一个整数。表示每个城市中小X的朋友数。
输出
输出有两行。
第一行为你选中的城市
第二行为最小需要的代价。
样例输入 Copy
5
0 1 2 0 0
1 0 0 0 20
2 0 0 10 0
0 0 10 0 1
0 20 0 1 0
2
3
4
5
6
样例输出 Copy
4
109
提示
对于100%的数据,n<=200,输出保证不超过long long int

思路:
这个题一开始做的时候,明白题意但是不会啊,基本无从下手,后来得到dalao指点,去学习了弗洛伊德最短路。这个题就是求出每两个城市之间的最短路径,然后去乘以相应的朋友数量,取最小值

int n;
ll ans,tmp,id;
ll dis[1000][1000],num[1000];
// i -> j 的最短路径的长度 
int main()
{int n;	scanf("%d",&n);memset(dis,0x3f3f3f3f,sizeof dis);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){ll x;	scanf("%lld",&x);if(x)//不为0时说明直接连通{dis[i][j] = x;}}}for(int i=1;i<=n;i++)	scanf("%lld",&num[i]);for(int k=1;k<=n;k++)//弗洛伊德最短路 O(n^3){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(dis[i][k] + dis[k][j] < dis[i][j]){dis[i][j] = dis[i][k] + dis[k][j];//求出两个城市之间的最短路径}}}}ans = 1e18 , id = -1;//赋ans一个很大的值for(int i=1;i<=n;i++){tmp = 0;for(int j=1;j<=n;j++){if(i != j)tmp += num[j] * dis[i][j];}if(ans > tmp){ans = tmp;id = i;}}printf("%lld\n%lld\n",id,ans);return 0;
}

这篇关于upc 个人训练赛第四场:黑匣子+选地址(优先队列+弗洛伊德最短路)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/282732

相关文章

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1502 MPI Maelstrom(单源最短路dijkstra)

题目真是长得头疼,好多生词,给跪。 没啥好说的,英语大水逼。 借助字典尝试翻译了一下,水逼直译求不喷 Description: BIT他们的超级计算机最近交货了。(定语秀了一堆词汇那就省略吧再见) Valentine McKee的研究顾问Jack Swigert,要她来测试一下这个系统。 Valentine告诉Swigert:“因为阿波罗是一个分布式共享内存的机器,所以它的内存访问

poj 3159 (spfa差分约束最短路) poj 1201

poj 3159: 题意: 每次给出b比a多不多于c个糖果,求n最多比1多多少个糖果。 解析: 差分约束。 这个博客讲差分约束讲的比较好: http://www.cnblogs.com/void/archive/2011/08/26/2153928.html 套个spfa。 代码: #include <iostream>#include <cstdio>#i

hdu 3790 (单源最短路dijkstra)

题意: 每条边都有长度d 和花费p,给你起点s 终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 解析: 考察对dijkstra的理解。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstrin

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 3255 次短路(第k短路) A* + spfa 或 dijkstra

题意: 给一张无向图,求从1到n的次短路。 解析: A* + spfa 或者 dijkstra。 详解见上一题:http://blog.csdn.net/u013508213/article/details/46400189 本题,spfa中,stack超时,queue的效率最高,priority_queue次之。 代码: #include <iostream>#i

poj 2449 第k短路 A* + spfa

poj 2449: 题意: 给一张有向图,求第k短路。 解析: A* + spfa。 一下转自:http://blog.csdn.net/mbxc816/article/details/7197228 “描述一下怎样用启发式搜索来解决K短路。 首先我们知道A*的基础公式:f(x)=g(x)+h(x);对h(x)进行设计,根据定义h(x)为当前的x点到目标点t所需要的实际距