算法练习——Multithreading

本文介绍了一个有趣的算法问题,通过特定的循环结构实现数字相加,旨在寻找能够达到目标值W的有效运算顺序。文章提供了问题背景、输入输出格式及示例,并分享了解题思路和C语言实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

  现有如下一个算法:
  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 22 1 2 1 1 1 1 2

样例输入

3 6
1 2 3

样例输出

Yes
1 1 2 2 2 2 3 33 3 3 3

数据规模和约定

  对于30%的数据,n<=4, n[i]的和小于10.
  对于100%的数据,n<=100 ,-10^9<=W<=10^9, 1<=n[i]<=1000

解析:

题目有点难理解,不过读完题目之后,我们大概可以得到几点有用信息:

1. 对于给定的n个循环,y的最大值为sum=a1+a2+…+an.这是因为,只有y := yi+1才会使得y的值加1,而这条语句  最多会执行sum次.

2.对于任意一次小循环中,先有yi=y,那么在其中插入任意长度的其它循环,然后再执行y=yi+1这条语句,所获得的结果一样,不受影响.从另一方面说可以消除一些不必要的循环.

故而,策略如下:

     首先sum=a1+a2+…+an,如果w<=0或者w>sum,那么必然是无解的.

     反之,如下分析

1.将ai按照大小排序,记得保留其原有的序号.

2.若a1 <=w,那么必然是可以的,我们只需要利用a[1]中的一个循环来消除所有不必要的加法.比如

         n=2  w=2  a1=1 a2=3

  则输出   1 2 2 22 1 2 2

3.若a1 >=w,

     (1)若 n==1 或者w==1,则无解.道理是显而易见的.

     (2)反之,即n>1,a1>w,w>1,这时候只是加a1就已经超了,所以,我们得想办法消除其中的加法.由于n>1,故而我们可以利用a2进行消除.思想为:利用a2中的一个小循环消除a1的a[1]-1次小循环,然后再输出w-2次a[2],然后利用剩下的一个a1来消除所有的不必要的循环.比如:

n=3  w=3  a1=4 a2=4a3=5

则输出    21 1 1 1 1 1 2 2 2 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 1

 

C代码如下:

#include <iostream>
#include <algorithm>
using namespace std;
typedef struct node{
   int id,value;
}data;
bool compare(node a,node b){
   return a.value<b.value;
}
int main()
{
   data a[1024];
   int w,n,sum=0;
   bool flag=true;
   cin>>n>>w;
   for(int i=0;i<n;++i){
       cin>>a[i].value;
       a[i].id=i+1;
       sum+=a[i].value;
    }
   if(sum<w || w<=0)
       cout<<"No"<<endl;
   else{
       sort(a,a+n,compare);
       if(a[0].value<=w){
           cout<<"Yes"<<endl;
           int rest=sum-w;
           //消除多余的
           cout<<a[0].id;
           int i=n-1;
           while(i>=0 && rest>=a[i].value){
                for(intj=0;j<a[i].value;++j){
                    cout<<''<<a[i].id<<' '<<a[i].id;
                }
                rest-=a[i].value;
                i--;
           }
           for(int j=0;j<rest;++j){
                cout<<''<<a[i].id<<' '<<a[i].id;
           }
           cout<<' '<<a[0].id;
           //输出剩下的
           a[0].value-=1;
           a[i].value-=rest;
           for(int j=0;j<=i;++j){
                for(intk=0;k<a[j].value;++k)
                    cout<<''<<a[j].id<<' '<<a[j].id;
           }
       }
        else if(n==1 || w==1)
           cout<<"No"<<endl;
       else{
           cout<<"Yes"<<endl;
           //1
           cout<<a[1].id;
           for(int j=0;j<a[0].value-1;++j)
                cout<<''<<a[0].id<<' '<<a[0].id;
           cout<<' '<<a[1].id;
           //w-2
           for(int j=0;j<w-2;++j)
                cout<<''<<a[1].id<<' '<<a[1].id;
           //1
           cout<<' '<<a[0].id;
           a[1].value=a[1].value-w+1;
           for(int i=1;i<n;++i){
                for(intj=0;j<a[i].value;++j){
                    cout<<''<<a[i].id<<' '<<a[i].id;
                }
           }
           cout<<' '<<a[0].id;
       }
    }
   return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值