zoukankan      html  css  js  c++  java
  • Java实现 蓝桥杯 算法训练 Multithreading

    问题描述

    现有如下一个算法:
      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
    
  • 相关阅读:
    leetcode5 Longest Palindromic Substring
    leetcode17 Letter Combinations of a Phone Number
    leetcode13 Roman to Integer
    leetcode14 Longest Common Prefix
    leetcode20 Valid Parentheses
    leetcode392 Is Subsequence
    leetcode121 Best Time to Buy and Sell Stock
    leetcode198 House Robber
    leetcode746 Min Cost Climbing Stairs
    tomcat下使用druid配置jnid数据源
  • 原文地址:https://www.cnblogs.com/a1439775520/p/13078380.html
Copyright © 2011-2022 走看看