问题描述

现有如下一个算法:

  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次)

输入格式

  第一行你会得到用空格分开的两个整数N(1<=N<=100)和W(-109<=W<=109),(N为需要算加法的数字个数,W是你希望算出的数)。

  第二行你会得到n个整数n[i] (1<=n[i]<=1000).

输出格式

  第一行您应该输出Yes(若能以某种顺序使得这个算法得出W的值) 或No。

  如果第一行是No,接下来就不用继续输出了。

  如果是Yes, 请在第2行输出2*sigma(n[i])个用空格隔开的数,表示任意一种满足条件的运算顺序。

样例输入

1 10

11

样例输出

No

样例输入

2 3

4 4

样例输出

Yes

1 1 2 1 2 2 2 2 2 1 2 1 1 1 1 2

样例输入

3 6

1 2 3

样例输出

Yes

1 1 2 2 2 2 3 3 3 3 3 3

数据规模和约定

  对于30%的数据,n<=4, n[i]的和小于10.

  对于100%的数据,n<=100 , -109<=W<=109, 1<=n[i]<=1000

初步看到此题,题意没看明白,前后仔细看了三四遍才整明白此题题意,竟无语吟噎…

此题意思一个形象的理解:输入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值进行划定区间,然后判断并找到相应输出结果。

下面具体代码中判断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.company;

import java.util.Scanner;

public class Multithreading {
//返回数组N中的最小元素数组下标
public static 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 static void runThread1(int[] N, int i) {
System.out.print((i+1)+" ");
N[i]--;
}
//从第i个进程开始,到第n个进程结束,顺序执行其中的每一个线程
public static 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 static 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){ 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();
printResult(N, w); }
}

运行结果:

请输入一个数字n和一个数字w:
2
请输入n个数字:
2
Yes
2 2 1 2 1 1 2 请输入一个数字n和一个数字w:
6
请输入n个数字:
2 3
Yes
1 2 2 2 2 3 3 3 3 3 3 3

Java实现 蓝桥杯 算法训练 Multithreading的更多相关文章

  1. Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)

    试题 算法训练 猴子吃包子 问题描述 从前,有一只吃包子很厉害的猴子,它可以吃无数个包子,但是,它吃不同的包子速度也不同:肉包每秒钟吃x个:韭菜包每秒钟吃y个:没有馅的包子每秒钟吃z个:现在有x1个肉 ...

  2. Java实现蓝桥杯 算法训练 大等于n的最小完全平方数

    试题 算法训练 大等于n的最小完全平方数 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 输出大等于n的最小的完全平方数. 若一个数能表示成某个自然数的平方的形式,则称这个数为完全平 ...

  3. java实现 蓝桥杯 算法训练 Password Suspects

    问题描述 在年轻的时候,我们故事中的英雄--国王 Copa--他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好记又难以破解.后来,他才知道这种密码是一个长度为奇数 ...

  4. Java实现 蓝桥杯 算法训练VIP 报数(暴力+数学)约瑟夫环问题

    试题 算法训练 报数 问题描述 现有n个同学站成一圈,顺时针编号1至n.从1号同学开始顺时针1/2报数,报到1的同学留在原地,报到2的同学退出圆圈,直到只剩一名同学为止.问最后剩下的同学编号. 输入格 ...

  5. Java实现蓝桥杯 算法训练 ALGO-15 旅行家的预算

    问题描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2.出发点每升汽油价格P和沿 ...

  6. Java实现 蓝桥杯 算法训练 审美课

    算法训练 审美课 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 <审美的历程>课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手.老师 ...

  7. Java实现 蓝桥杯 算法训练 多阶乘计算

    试题 算法训练 多阶乘计算 问题描述 我们知道,阶乘n!表示n*(n-1)(n-2)-21, 类似的,可以定义多阶乘计算,例如:5!!=531,依次可以有n!..!(k个'!',可以简单表示为n(k) ...

  8. Java实现 蓝桥杯 算法训练 找零钱

    试题 算法训练 找零钱 问题描述 有n个人正在饭堂排队买海北鸡饭.每份海北鸡饭要25元.奇怪的是,每个人手里只有一张钞票(每张钞票的面值为25.50.100元),而且饭堂阿姨一开始没有任何零钱.请问饭 ...

  9. Java实现 蓝桥杯 算法训练 第五次作业:字符串排序

    试题 算法训练 第五次作业:字符串排序 问题描述 输入一个小写字符串,按从小到大的顺序输出. 输入格式 bcaed 输出格式 abcde 顶格输出,中间没有空格 样例输入 一个满足题目要求的输入范例. ...

随机推荐

  1. C#语言实现推箱子

    话不多说直接上代码 using System; namespace Boxer { class Program { const int WIDTH = 8; const int HEIGHT = 8; ...

  2. 解决Eclipse添加新server时无法选择Tomcat7.0

    新添加tomcat时 出现如下图情况: 解决方法:这时打开工作空间目录下的.metadata\.plugins\org.eclipse.core.runtime\.settings文件夹,删除org. ...

  3. 我的linux学习日记day7

    一.文件权限: r:read 读取文件列表的权限, 数字4表示 w:write 写入.删除.修改的权限,数字2表示 x:execute 进入目录的权限,数字1表示 权限分配:文件所有人.文件所属主.其 ...

  4. es7,8 临门一脚。

    ES7 1.Array.prototype.includes() includes()作用,是查找一个值在不在数组里,若是存在则返回true,不存在返回false. 1.基本用法: ['a', 'b' ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 自定义仓储之增删改查

    上一篇文章(https://www.cnblogs.com/meowv/p/12913676.html)我们用Code-First的方式创建了博客所需的实体类,生成了数据库表,完成了对EF Core的 ...

  6. JDBC基本使用方法

    JDBC基本使用方法 JDBC固定步骤: 加载驱动 String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true& ...

  7. hdu2093 考试排名(还需完善)

    下面代码是借鉴的.好多的知识点等着完善 #include <iostream> #include <string> #include <algorithm> usi ...

  8. js-实现多列布局(瀑布流)

    本文是使用面向对象的思想实现多列布局(瀑布流).当然,使用面向过程也能实现,具体效果图和案例如下: 具体实现代码如下: <!DOCTYPE html> <html lang=&quo ...

  9. [不得不知道系列]Java线程面试你不得不知道的基础知识一

    Java内存管理面试指南一 Java基础面试指南一 Java基础面试指南二 Java基础面试指南三 Java基础面试指南四 Java线程面试指南一 Java线程面试指南二 Redis面试指南一 Kaf ...

  10. corosync+pacemaker实现httpd高可用

    corosync+pacemaker 官方网址 https://clusterlabs.org/ 一.开源高可用了解 OPEN SOURCE HIGH AVAILABILITY CLUSTER STA ...