算法笔记_052:蓝桥杯练习Multithreading(Java)
目录
1 问题描述
repeat ni times
yi := y
y := yi+1
end repeat
令n[1]为你需要算加法的第一个数字,n[2]为第二个,...n[N]为第N个数字(N为需要算加法的数字个数),
并令y初始值为0,先令i=1运行这个算法(如上所示,重复n[i]次),然后令i=2运行这个算法。。直到i=N。注意y值一直不要清零。最后y的值就是你需要的加法答案。
你想知道,有没有某种运算顺序能使答案等于W。
一个循环中的全部语句,是不能改变在总的语句排列中的相对顺序的。
(这里的第i个循环是指这n[i]*2条语句。就是你把属于第i个循环的语句抽出来看,它们需要按照原顺序排列。在你没有运行完这个循环的最靠前一条未完成的 语句的时候,你是不能跳过它先去完成这个循环后面的语句的。你能做的仅是把若干个循环按照你所规定的顺序“归并”起来。)
举个例子,n[1]= 2 ,n[2]=1, W=1.一种可行的运算顺序是“2 1 1 1 1 2”,数字为几表示运行第几个算法的下一条语句(你可以看到”1”出现了4次,是因为n[1]=2即循环两次,而每次循环里面有两条语句,所以2*2=4次)
| y值 | y[1] 值 | y[2] 值 | |
| 执行0条语句过后 | 0 | 0 | 0 |
| 执行1条过后(y[2]=y) | 0 | 0 | 0 |
| 执行2条过后(y[1]=y) | 0 | 0 | 0 |
| 执行3条过后(y=y[1]+1) | 1 | 0 | 0 |
| 执行4条过后(y[1]=y) | 1 | 1 | 0 |
| 执行5条过后(y=y[1]+1) | 2 | 1 | 0 |
| 执行6条过后(y=y[2]+1) | 1 | 1 | 0 |
可以看到,最后y值变成了1,也就完成了我们的任务。
第二行你会得到n个整数n[i] (1<=n[i]<=1000).
如果第一行是No,接下来就不用继续输出了。
如果是Yes, 请在第2行输出2*sigma(n[i])个用空格隔开的数,表示任意一种满足条件的运算顺序。
11
4 4
1 1 2 1 2 2 2 2 2 1 2 1 1 1 1 2
1 2 3
1 1 2 2 2 2 3 3 3 3 3 3
对于100%的数据,n<=100 , -10^9<=W<=10^9, 1<=n[i]<=1000
2 解决方案
初步看到此题,题意没看明白,前后仔细看了三四遍才整明白此题题意,竟无语吟噎......
此题意思一个形象的理解:输入n个数:N[0]、N[1]、...、N[n-1],和一个对照结果数w。把其中每一个N[i]看成一个进程,而N[i]具体值看成是这个进程所包含的线程数。例如,N[2] = 6,进程2有12个线程,如果结果输出Yes,则必定要输出12个2。为什么是12个2呢?因为执行一次循环,里面包含2个语句,6*2 = 12,所以进程2包含12个线程,且这12个线程的中间可以执行其它进程(例如:N[3])的线程,但是这12个线程的执行先后顺序不能打乱。不管有多少个进程,最后一个线程一定是执行y = y[i] + 1;即本题要求我们输出当y == w时的所有线程的一种可能执行顺序。
由y[i] = y; y = y[i] + 1;..执行规律可知,n个进程执行返回的最大y值maxY = N[0] + N[2] + ... +N[n-1]。(PS:因此,执行一次完整的循环,即执行两个语句,y的值自增1,且y的值可以向下传递)
那么,到这里,请看一种特例:当N[1] = 1时,y[1] = y = 0; ...(PS:除了进程1之外的所有进程均执行完毕)...,y = y[1] + 1 = 1,从而得到最后y的结果为1。
此时,我们可以初步想到y的结果一定满足 1 <= y <=maxY。
由题意中给定的w值输入范围,可以轻松得到大部分输出No的情况。
分析到这里,相信大家已经对于此题有了初步编码框架:即对w值进行划定区间,然后判断并找到相应输出结果。
但是,本文也有一点遗憾,在蓝桥杯练习系统里最终的测评分为95分,其中的测试数据5运行错误,由于没有VIP特权,不能查看输入和输出测试数据,我自己也查看了代码逻辑好大一会也没有检查出具体逻辑错误>~<。(PS:在本文最后给出的参考资料链接中,那位网友的代最终码运行结果是100分,大家也不妨参考一下~)

下面具体代码中判断Yes的情况核心思想:
先执行count = (w-2)*2个线程,返回此时的进程数i,这时可以轻松得知temp[i] = w -2,再执行除去进程i的所有线程数目总和减去2的结果的连续的线程,再执行一次进程i中的线程,这时y = temp[i]+1=w-1,再执行一次按照前后顺序排列的线程倒数第2个线程,出现temp[N.length-1] = y =w-1,然后执行完进程i中剩下的线程,最后执行按照前后顺序排列的线程的最后一个线程,返回y = temp[N.length-1]+1 =w。
如果没看懂上面所说思想,下面代码注释应该能够看明白。
具体代码如下:
package com.liuzhen.systemExe;
import java.util.Scanner;
public class Main{
//返回数组N中的最小元素数组下标
public int getMinI(int[] N) {
int min = 0;
for(int i = 0;i < N.length;i++) {
if(N[i] < N[min])
min = i;
}
return min;
}
//执行第i个进程中的一个线程,执行完后,总线程数减1
public void runThread1(int[] N, int i) {
System.out.print((i+1)+" ");
N[i]--;
}
//从第i个进程开始,到第n个进程结束,顺序执行其中的每一个线程
public void runThread2(int[] N, int i, int n) {
for( ;i <= n;i++) {
while(N[i] > 0) { //执行第i个进程中的每一个线程
System.out.print((i+1)+" ");
N[i]--;
}
}
}
public void printResult(int[] N, int w) {
int maxY = 0; //计算N个进程,依次执行能够得到的最大y值
for(int i = 0;i < N.length;i++) {
maxY += N[i];
N[i] *= 2; //此处乘以2表示,第i个线程需要执行的语句个数(因为执行一次循环,有两条语句)
}
//(1)当w <= 0时,输出No
if(w <= 0)
System.out.println("No");
//(2)当w == 1时,此时要看N[i]的最小值,才能决定输入Yes或者No
else if(w == 1) {
int min = getMinI(N);
if(N[min] == 2) { //由于前面N[i] *= 2,此处N[min] == 2表示执行一次循环需要执行两句
System.out.println("Yes");
runThread1(N,min); //执行一次进程min中的第一个线程,此时y[0] = 0
if(min == 0) //执行完成除了进程min之外的所有进程
runThread2(N, 1, N.length-1);
else {
runThread2(N, 0, min-1);
runThread2(N, min+1, N.length-1);
}
runThread1(N,min); //执行进程min中的第二个线程,此次y = y[0] + 1 = 1
} else {
System.out.println("No");
}
}
//(3)当数组N长度为1时,w不等于N[0]执行完整循环次数,输出No
else if(N.length == 1 && w > 1 && w < maxY) {
System.out.println("No");
}
//(4)当数组N长度为1时,w等于N[0]执行完整循环次数,输出Yes
else if(N.length == 1 && w == maxY) {
System.out.println("Yes");
while(N[0] > 0)
runThread1(N, 0);
}
//(5)当数组N的长度不等1且1 < w <= maxY时,此时一定会输出Yes
else if(N.length != 1 && w > 1 && w <= maxY) {
System.out.println("Yes");
/*
* 下面代码注解中tempY[i]表示题目中第i个进程的yi
* y表示题目循环中的y
*/
int count = (w-2)*2;
if(count == 0) {
int tempI = 0;
for(int i = 0;i < N.length-1;i++) {
if(N[i] >= 4) { //表示N[i]至少能够进行完整的2次循环,共四个语句
tempI = i;
break;
}
}
runThread1(N, tempI); //执行1次,此时tempY[tempI] = 0
if(tempI == 0)
runThread2(N, 1, N.length-2);
else {
runThread2(N, 0, tempI-1);
runThread2(N, tempI+1, N.length-2);
}
while(N[N.length-1] > 2) {
runThread1(N, N.length-1);
}
runThread1(N, tempI); //此时,y = tempY[tempI] + 1 = 1
runThread1(N, N.length-1); //此时,tempY[N.length-1] = y = 1
while(N[tempI] > 0) { //执行完N[tempI]中剩余的线程
runThread1(N, tempI);
}
runThread1(N, N.length-1); //此时执行最后一个线程,y = tempY[N.length-1] + 1 = 2
} else {
int i = -1;
//从第0个进程开始,执行到第i个进程,当tempY[i] = w-3, y = w - 2时结束
while(count > 0) {
i++;
while(N[i] > 0) {
runThread1(N, i); //此处执行两次runThread1表示执行一次整个循环,y值便会自增1
runThread1(N, i);
count = count - 2;
if(count == 0)
break;
}
}
runThread1(N, i); //执行完此句,此时tempY[i] = w - 2
runThread2(N, i+1, N.length-2); //执行进程i+1到 N.length-2之间的所有线程
while(N[N.length-1] > 2) { //执行最后一个进程中的线程
runThread1(N, N.length-1);
}
runThread1(N, i); //执行完此句,此时y = tempY[i] + 1 = w - 1
runThread1(N, N.length-1); //执行完此句,此时tempY[N.length-1] = y = w - 1
while(N[i] > 0) { //执行完进程i中剩余的线程
runThread1(N, i);
}
runThread1(N, N.length-1); //这是最后一个线程,执行完后,y = tempY[N.length-1] + 1 = w
}
}
//(6)当w > maxY时,输出No
else if(w > maxY) {
System.out.println("No");
}
}
public static void main(String[] args){
Main test = new Main();
Scanner in = new Scanner(System.in);
// System.out.println("请输入一个数字n和一个数字w:");
int n = in.nextInt();
int w = in.nextInt();
// System.out.println("请输入n个数字:");
int[] N = new int[n];
for(int i = 0;i < n;i++)
N[i] = in.nextInt();
test.printResult(N, w);
}
}
运行结果:
请输入一个数字n和一个数字w:
2 2
请输入n个数字:
2 2
Yes
1 2 2 1 2 1 1 2 请输入一个数字n和一个数字w:
3 6
请输入n个数字:
1 2 3
Yes
1 1 2 2 2 2 3 3 3 3 3 3 3
参考资料:
算法笔记_052:蓝桥杯练习Multithreading(Java)的更多相关文章
- 算法笔记_083:蓝桥杯练习 合并石子(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数.求把所有石子 ...
- 算法笔记_107:蓝桥杯练习 算法提高 学霸的迷宫(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗.但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要 ...
- 算法笔记_096:蓝桥杯练习 算法提高 求最大值(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 给n个有序整数对ai bi,你需要选择一些整数对 使得所有你选定的数的ai+bi的和最大.并且要求你选定的数对的ai之和非负,bi之和非负 ...
- 算法笔记_091:蓝桥杯练习 递推求值(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 已知递推公式: F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5, F(n, 2)=F(n-1, 1) + 3F(n- ...
- 算法笔记_056:蓝桥杯练习 未名湖边的烦恼(Java)
目录 1 问题描述 2 解决方案 2.1 递归法 2.2 递推法 1 问题描述 问题描述 每年冬天,北大未名湖上都是滑冰的好地方.北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰 ...
- 算法笔记_055:蓝桥杯练习 Tricky and Clever Password (Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 在年轻的时候,我们故事中的英雄——国王 Copa——他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好 ...
- 算法笔记_076:蓝桥杯练习 结点选择(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 有一棵 n 个节点的树,树上每个节点都有一个正整数权值.如果一个点被选择了,那么在树上和它相邻的点都不能被选择.求选出的点的权值和最大是多 ...
- 算法笔记_060:蓝桥杯练习 出现次数最多的整数(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 编写一个程序,读入一组整数,这组整数是按照从小到大的顺序排列的,它们的个数N也是由用户输入的,最多不会超过20.然后程序将对这个数组进行统 ...
- 算法笔记_067:蓝桥杯练习 算法训练 安慰奶牛(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是 ...
随机推荐
- HTML5+中动态构建列表并填充数据
部分代码参考demo----<历史上的今天>. 感谢作者的分享,愿好人一生平安,虽然只有两个页面,但是通过这个示例让我学会了5+中如何动态构建列表并填充数据,非常实用. html部分: & ...
- 用jquery实现文章自动生成二级目录
前段时间有个同学问有没有办法在博客园上发一篇文章然后自动生成文章的目录.之前不知道该怎么做这几天看了些jquery之后觉得还是容易的. 一级目录 一级目录的思路很简单,找出作为一级标题的元素,在某个地 ...
- 使用phonegap开发安卓HLS播放软件解决方案
目前使用phonegap开发的手机应用,很少涉及视频播放的功能,究其原因,主要是phonegap提供的API里面对视频播放功能支持度不够,当然播放音频一般情况下还是能够实现的,由于工作需要,自己研究了 ...
- 【20181024T3】小C的宿舍【分治】
题面 [错解] 好像就是\(|i-j|+|a_i - b_i|\)唉 嗯开始都加i-1,跑一遍,1~(i-1)加1,i~n 减1,线段树维护. 过样例了呢 哎大样例怎么多了那么多啊 跑了个暴力,多得更 ...
- 【Floyd】文化之旅
[NOIP2012]文化之旅 题目描述 有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一 种文化超过一次(即如果他学习了某种文化,则他就不能到达其他有这种文化的国家).不 ...
- BZOJ 2818 Gcd(莫比乌斯反演)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2818 [题目大意] 给定整数N,求1<=x,y<=N且Gcd(x,y)为素 ...
- BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1827 [题目大意] 给出一棵有点权和边权的树, 请确定一个点,使得每个点到这个点的距离 ...
- [SRM568]DisjointSemicircles
题意:$2n$个位置排成一列,有一些位置已经填了数字($0\cdots n-1$中每个数字出现$0$次或$2$次),问是否存在一种填数方案使得用$n$个不相交的半圆可以把相同的数字连起来 首先把所有已 ...
- NOIP2014 解题报告·水渣记
Day 1: 第一次参加noip.小激动,小紧张,这些正常的情绪就不用说了.唯一值得一提的是 我早上步行去郑大工学院的时候迷路了,直接转进了隔壁的河南农大,绕了半天找不到机房,还给几个同学打了电话可就 ...
- window下命令行的方式安装svn服务端
下载Binary Packages类型的 安装文件 https://www.visualsvn.com/server/download/ 自己选择版本 第一步 :开始安装到 c:/software ...