Sticks

C - Sticks
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%lld & %llu
Submit

Status
Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
Output
The output should contains the smallest possible length of original sticks, one per line.
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5

题意
给出一定数量的小木棒的长度,它是由等长的若干木棒随意砍断所得到的。对于给定的一组小木棒,请求出原始木棒的最小长度。

思路:
1.看到这个题,就是要把小棒一个个进行比较,看能不能恢复若干个原棒。但这样枚举效率太低。

2.这里用深度优先搜索来遍历(递归实现)速度较
3.假设原始木棒的长度已定,那么由若干小棒来组成一根这样的棒后,其它的原棒将不再由这些已经用过的小棒来拼接了。我们可以设置visited数组来标记这些已经“成功”拼接的木棒,而不是已经用过的木棒。
4.那么原始木棒长度有多长,不至于从0一直往后试探吧?这样太麻烦。因为长度最小的原棒,它的长度不会比目前最大的小棒还短。长度最大的原棒的长度不会比所有小棒的长度和还长。这样范围就确定了。

5.我们用深搜用什么参数呢?
首先应该是对某个可能存在的长度(原棒长)进行试探性的验证,看是否能由这所有的小棒组成。那么这个参数是必须的,记为len。然后,每当“成功”接收一根小木棒(前提是这根小木棒的接收能导致一根完整的木棒被拼出,而不是暂时被接收),那么可用的小木棒数就会相应减1.这个参数很重要(记为num)。
再就是对我们要试探的原木棒可能取值,每当它成功接收一根小木棒,还需要用来拼接一根原木棒的长度就会减小。这也是搜索过程必须知道的量,当它减小到0时,说明一根原木棒拼接完成,它将重新被赋值为len,从而进行下一根木棒的搜索。可知这个参数同样很重要(记为remains_len)。
6.由于过程中要确定某根小棒是否确定成功被接收,它就得提前预知加入这根小棒后其它的小木棒能不能匹配成功,就叫要求在遍历某个小木棒时,对其后的木棒进行递归搜索(深搜的特点),若能匹配成功,则标记当前小木棒为用过,可以直接返回(试探成功);若不能匹配,说明此棒目前不可用,将标记取消,待下一次搜索用。若当前木棒不可用,那么与这根小木棒长度相同的木棒也将不可用,直接跳过(剪枝),而且若这个小木棒的长度刚好是reamins_len的长度,那么更能说明后面的不能匹配了,因为如此合适的小棒被接收都不能导至试探成功,后面的小棒更不可能,直接返回0(试探失败 )(剪枝)。还有就是如果len=remains_len(说明这是新一根原棒,还没有进行匹配),而在预先判断匹配与否时已经判断不能匹配,这样都不能匹配,那么说明以后都不能匹配了(这就是深搜的效果了)。返回0(试探失败)(剪枝)。
7.当remains_len=0&&num=0说明能用的棒已经没有,而且拼成一根原棒还需的长度为0,只能表示原棒已经完整的由这所有的小棒拼接出来。此时只需返回len(试探成功),这个操作应该放在函数最前。
8.如果深搜完成,仍未返回试探成功,到了函数的最后,只能说明这个试探失败。直接返回0.
9.为了让用过但没有被成功接收的小木棒再次利用,所以函数里对每个小棒进行一次搜索。以让这些漏网的小木棒或许能被再次利用。
10.注意:当换一个原木棒长度进行试探时,要置visited为0,否则会与上次搜索混在一起

#include"iostream"
//#include"stdlib.h" 
using namespace std;
int a[69];//存小棒长大小最好大于64
int visited[69];//标记小棒是否被用
int n;//小棒个数 
int cmp(const void *a,const void *b)
{
    return *(int*)b-*(int*)a; 
} 
/*DFS:递归搜索,以剩下小棒数和拼接一根棒所需长度作为递归参数*/ 
int DFS(int len,int remains_len,int num)/*作为搜索的棒长len,拼成len长的棒还需的长度remains_len,剩下的未作为拼接的小棒个数num*/
{
    if(remains_len==0&&num==0)/*当还需长度为0且未作接接的小棒个数为0时,说明拼接成功*/
    return len;
    if(remains_len==0)/*当完成拼接一个棒时,要重新进行下一根木棒拼接,给remains_len重新赋值*/
    remains_len=len;
    for(int i=0;i<n;i++)
    {
            if(visited[i]==1)/*已经作为成功拼接的小棒,不再作为拼接对象*/ 
            continue; 
            if(remains_len>=a[i])
            {
                 visited[i]=1;/*暂时标记为已经用了*/ 
                 if(DFS(len,remains_len-a[i],num-1))/*当接受这根小棒a[i],能完成所有任务,则返回成功拼接棒长*/ 
                 return len;
                 visited[i]=0;/*当用a[i]不能完成任务就不用此棒,将其标记为该步未用此棒*/ 
                 if(a[i]==remains_len||len==remains_len)/*a[i]=remains_len或remians_len=len时本来表示即将拼成一根棒,或刚进行新一轮拼接(即if中判断的是主问题性质完全相同的子问题)但经过上面的if判断,子问题不能完成所有任务,
                 那么整体不可能完成任务,不再考虑,搜索失败(剪枝)*/ 
                 break; 
                 while(a[i]==a[i+1])/*当a[i]不能完成任务,与它相同的小棒也不能完成任务(剪枝) */
                 i++; 
            } 
    } 
    return 0; 
} 
int main()
{
    while(cin>>n&&n)
    {
                    int sum=0;//所有小棒长度
                    int len,k;
                    for(int i=0;i<n;i++)
                    {
                            cin>>a[i];
                            sum+=a[i]; 
                    } 
                    qsort(a,n,sizeof(int),cmp);
                    for(len=a[0];len<=sum;len++)
                    {
                        memset(visited,0,sizeof(visited));/*每次尝试都要置所有小棒为可用*/
                        if(sum%len==0)
                        {
                                     k=DFS(len,0,n); 
                                      if(k) 
                                        break; 
                        }
                    }
                    cout<<k<<endl; 
    } 
    return 0;
}
好的,这是一个比较经典的小游戏,我可以用C语言帮您实现。以下是代码实现: ```c #include <stdio.h> int main() { int sticks = 21; // 初始火柴数 int take, computerTake; // 玩家和计算机取的火柴数 printf("Game begin:\n"); while (sticks > 0) { printf("%d sticks left in the pile.\n", sticks); printf("How many sticks do you wish to take (1~4)? "); scanf("%d", &take); while (take < 1 || take > 4 || take > sticks) { printf("Illegal move. Please try again.\n"); printf("How many sticks do you wish to take (1~4)? "); scanf("%d", &take); } sticks -= take; if (sticks == 0) { printf("%d sticks left in the pile.\n", sticks); printf("You have taken the last sticks.\n"); printf("***You lose!\nGame Over.\n"); break; } computerTake = (5 - take) % 5; printf("%d sticks left in the pile.\n", sticks); printf("Computer take %d sticks.\n", computerTake); sticks -= computerTake; if (sticks == 0) { printf("%d sticks left in the pile.\n", sticks); printf("Computer has taken the last sticks.\n"); printf("***You win!\nGame Over.\n"); break; } } return 0; } ``` 程序中,我们使用了一个 while 循环,不断进行玩家和计算机的取火柴操作,直到火柴数量为 0。每次玩家取火柴前,都会判断其取的火柴数量是否合法,不合法则要求重新输入。而计算机则根据玩家取的火柴数量,采用一定的策略来取火柴。这里,我们使用了一个简单的策略:让计算机取的火柴数量加上玩家取的火柴数量等于 5。这样,计算机就可以在保证不输的前提下,尽可能地拖延游戏进程,增加玩家输的可能性。 运行程序后,可以按照提示进行游戏。如果您想让计算机更聪明一些,可以尝试采用其他的策略,比如根据当前剩余的火柴数和玩家的取火柴数量,来决定计算机应该取多少火柴。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值