蓝桥杯 MultiThreading(C++)

题目

问题描述

现有如下一个算法:

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(1<=N<=100)和W(-10^9<=W<=10^9),(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 , -10^9<=W<=10^9, 1<=n[i]<=1000

 

来自 <http://lx.lanqiao.cn/problem.page?gpid=T347>

题目理解


我们从输入的要求和解释可以看出N是数组的具体个数,w是期待值,也就是算法中y的值,然后数组里每个元素的值就代表了算法的循环次数(如N[1]=2的具体运算步骤为:y[1]=y=0,y=y[1]+1=1;y[1]=y=1,y=y[1]+1=2,这样执行2次算法,每次都是执行2条语句),不过一个执行过程的语句顺序不能变,例如执行了N1的第一条语句 y[1]=y=0 后,下次执行N1必须是接着第二条语句 y=y[1]+1 执行。但是第一条语句和第二条语句之间是可以执行其他的过程N2N3,N3……..

代码思路

    • 不论在一个进程执行的 2条语句之间放多少过程语句,y 的值不会受到该过程中间那些其他的过程语句干扰,不明白的可以回顾题目中例子的执行步骤。
    • 期待值w1时:不论输入多少个元素,必须有一个元素是1,否则肯定是不满足w的(注意这一点,我一直忽略了这种情况导致只有95分)
    • 当只有一个元素时,只有该元素等于w一种情况才能满足w
    • 当有多个元素时,我们先对元素从小到大排序,然后将元素值相加(从第一个元素开始相加),最后对相加结果sum分情况:
      • Sum<0:不可能满足w
      • Sum=0:肯定能满足w,只要sum里的元素之外的元素放到第一个过程的第一条语句和第二条语句中
      • Sum>0:肯定能满足w,有2中可能:第一个元素大于w,前几个元素的结果大于w
        • 第一种情况:由于从小到大排序,所以N2>N1值。先用一个N2过程消除使得N1过程只剩一个,然后将N2过程执行到  y=w-1,最后用唯一的N1过程消除其他过程
        • 第二种情况:求出sumw的差距t(t=sum-w),先用一个N1过程消除 t sum中最后一个元素多出的过程和sum之后的元素过程,然后开始执行剩下的过程。

代码实现

#include

#include

using namespace std;

 

struct Num{

int pos;

int value;

};

//比较函数

int comp(const void* pa,const void* pb){

Num* a=(Num*)pa;

Num* b=(Num*)pb;

if(a->value!=b->value){

return a->value-b->value;

}else{

return a->pos-b->pos;

}

}

 

const int maxLen=101;

int main(){

//输入数组长度,期待值,数组的值

int len,w;

cin>>len>>w;

Num nums[maxLen];

for(int index=1;index<=len;index++){

cin>>nums[index].value;

nums[index].pos=index;

}

if(w==1){

int numIndex=1;

for(;numIndex<=len;numIndex++){

if(nums[numIndex].value==1){

cout<<"Yes"<

//用值为1的数组消除其他数组

cout<

for(int index=1;index<=len;index++){

if(index!=numIndex){

for(int j=0;j

cout<

}

}

}

cout<

return 0;

}

}

cout<<"No"<

return 0;

}

//如果只输入一个数,只有该数等于期待值才能满足条件

if(len==1){

if(nums[1].value==w){

cout<<"Yes"<

for(int index=0;index

cout<

}

}else{

cout<<"No"<

}         

}else{

//从小到大排序

qsort((void*)(nums+1),len,sizeof(Num),(int(*)(const void*,const void*))comp);

//数组索引从1开始,计算数组的和

int sum=0;

int numIndex=1;

//如果总数大于等于期待值就跳出

for(;numIndex<=len;numIndex++){

sum+=nums[numIndex].value;

if(sum>=w){

break;

}

}

//如果总数小于期待值肯定不能的

if(sum

cout<<"No"<

}else if(sum==w){  //如果前面数的和刚好等于期待值

cout<<"Yes"<

cout<

for(int j=numIndex+1;j<=len;j++){

for(int k=0;k

cout<

}

}

cout<

//因为执行过一次

nums[1].value--;

for(int j=1;j<=numIndex;j++){

for(int k=0;k

cout<

}

}

}else{

//第一个数就大于w,或几个数加起来才大于w

cout<<"Yes"<

if(numIndex==1){

cout<

//只保留第一数组的1

for(int index=0;index

cout<

}

//3以后的数字都消除

for(int index=3;index<=len;index++){

for(int j=0;j

cout<

}

}

cout<

//因为执行过一次

nums[2].value--;

//2执行到 y=w-1

for(int index=0;index

cout<

nums[2].value--;

}

cout<

for(int index=0;index

cout<

}

cout<

}else{

int t=sum-w;

cout<

//消除当前数组多出的循环

for(int index=0;index

cout<

nums[numIndex].value--;

}

//消除当前数组之后的循环

for(int index=numIndex+1;index<=len;index++){

for(int j=0;j

cout<

}

}

cout<

//因为执行过一次

nums[1].value--;

//把之前的都输出

for(int index=0;index<=numIndex;index++){

for(int j=0;j

cout<

}

}

}

}

}

return 0;

}

结果截图

蓝桥杯 MultiThreading(C++)_第1张图片

参考文献:

算法训练 Multithreading实现-知乎:https://www.zhihu.com/question/39646338

你可能感兴趣的:(c++,蓝桥杯)