Sticks

问题描述:http://acm.pku.edu.cn/JudgeOnline/showproblem?problem_id=1011

主要想用回溯法的思想解决它。关键是要确定搜索的顺序。要提高算法的效率还要找到合适的剪枝。

// Sticks1.cpp : Defines the entry point for the console application.
// http://acm.pku.edu.cn/JudgeOnline/showproblem?problem_id=1011
// 首先将所有的小棒按从大到小的顺序排序
// 搜索策略:
// 每次用小棒组成原始棒,都要用到当前剩余的最长的小棒
// 搜索每根原始棒的时候,组成它的每个小棒的长度由大到小排列,
// 所以Search的时候有个startno,表示搜索下一个小棒的时候,从startno开始搜索
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;

short len[64];
bool b[64];
short n,poslen,sticks;

//stickno为要组装的第几根原始棒,startno为组装第stickno个原始棒的时候,从第startno个小棒开始查找,
//leftlen表示组装第stickno个原始棒的时候,还缺多leftlen的长度
bool Search(short stickno, short startno, short leftlen)
{
 //搜索到最后一个原始棒,剩余的小棒的总长度必然等于原始棒的长度
 if(stickno==sticks-1) return true;

 //搜索第stickno个原始棒,如果第stickno个小棒还没使用,表明
 //第stickno个小棒不能参与组成原始棒,则整个搜索失败
 if( stickno>0 && !b[stickno-1] ) return false;

 for(int i=startno; i<n; i++)
 {
  if(!b[i])
  {
   //如果有连续的几根小棒长度相等,且前一个小棒不被使用,则当前小棒也不能使用,避免重复搜索
   if( (i>0)&&(!b[i-1]) && (len[i-1]==len[i])) continue;

   //正好组成一个原始棒
   if(len[i]==leftlen)
   {
    b[i] = true;
    //搜索下一个原始棒,如果成功则返回true,如果失败,则回溯
    if (Search(stickno+1,0,poslen)) return true;
    b[i] = false;
   }
   else if(len[i]<leftlen)
   {
    int j = n-1;
    while(b[j])
     j--;
    
    if(len[i]+len[j]<=leftlen)
    {
     b[i] = true;
     if(Search(stickno,i+1,leftlen-len[i])) return true;//此处的第二个参数设为i+1非常关键,提高了搜索速度
     b[i] = false;
    }
   }
  }
 }

 return false;
}

void main()
{
 short i,maxlen,totallen;
 cin>>n;
 while(n)
 {
  maxlen = totallen = 0;

  for(i=0; i<n; i++)
  {
   cin>>len[i];
   if(len[i]>50)
    len[i]=0;
   totallen += len[i];
   if(len[i]>maxlen)
    maxlen = len[i];
  }

  //对每小段的大小按从大到小的顺序排序
  sort(&len[0],&len[n],greater<int>());
  //清除长度为0的棒
  i=0;
  while((i<n)&&(len[i]>0)) i++;
   n = i;

  for(poslen=maxlen; poslen<totallen; poslen++)
  {
   //棒的个数不为整数则改变poslen的大小再试
   if(totallen%poslen) continue;

   //将所有小段设为未选择
   memset(b,0,n*sizeof(bool));

   //为每根长度为poslen的stick找到各个小段,这些小段的和为poslen
   sticks = totallen / poslen;
   if(Search(0,0,poslen))
    break;
  }
  cout<<poslen<<endl;

  cin>>n;
 }
}

好的,这是一个比较经典的小游戏,我可以用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、付费专栏及课程。

余额充值