the blocks problem(uva 101 or poj 1208)

C语言解决积木搬运问题
本文详细介绍了如何使用C语言解决积木搬运问题,包括理解题目中的指令、选择合适的链表数据结构、处理特殊情况进行代码优化。文章提供了两种解决方案,一种是使用链表操作,另一种是使用栈进行操作,并在代码实现中遇到并解决了错误。

题目描述见:uva 101 or poj 1208

关键在于彻底理解题目中搬积木的几个命令的含义,见具体分析

如果还不能理解题意,那么找一个正确通过的代码,编译并输入测试数据,查看其每一个命令的执行情况。如我的代码中162行注释内容取消后即可显示每一步执行后当前积木的情况)

这个题目似乎没有合适的数据结构,由于插入删除操作较多,所以直接用了链表,并且使用双重指针,差点把自己搞晕。(另外,刚开始写的代码能在poj1208上通过,但不能在uva 101上通过,后来发现是141行中的continue误写成了break。网上也有类似的情况,似乎是因为没有考虑到特殊情况的处理(即两个积木块号相同或者处于同一列时需要忽略该命令))

相关C语言代码:

/* uva 101 or poj 1208 */
/*the Blocks problem */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct node {
  int data;
  struct node *prev;
  struct node *next;
};
typedef struct node *pBlock;
static void CreateHeader(pBlock *ppBlk)
{
  pBlock newBlk = malloc(sizeof(*newBlk));
  newBlk -> next = newBlk->prev = NULL;
  (*ppBlk) = newBlk;
}
static void InsertOnFirst(pBlock *ppBlk,  int data)
{
  pBlock newBlk = malloc(sizeof(*newBlk));
  newBlk -> data = data;
  newBlk -> next = NULL;
  newBlk -> prev = *ppBlk;
  (*ppBlk)->next = newBlk;
}
static int FindBlock(pBlock *ppBlk, int blockNumber, pBlock *ppretBlock)
{
  pBlock tmpBlk = (*ppBlk)->next;
  while(tmpBlk != NULL)
    if(tmpBlk->data == blockNumber)
      {
	*ppretBlock = tmpBlk;
	return 1;
      }
    else
      tmpBlk = tmpBlk->next;
  return 0;
}
static void PopAllFollowBlks(pBlock *ppBTab,pBlock *ppBlk)
{
  pBlock tmpBlk,curBlk = (*ppBlk)->next;
  (*ppBlk)->next = NULL;
  while(curBlk != NULL)
    {
      tmpBlk = curBlk;
      curBlk = curBlk->next;
      ppBTab[tmpBlk->data] ->next = tmpBlk;
      tmpBlk->next = NULL;
      tmpBlk->prev = ppBTab[tmpBlk->data];
    }
}
      
      
static void MoveOnto(pBlock *ppBTab,pBlock *ppSrcBlk, pBlock *ppDstBlk)
{
  PopAllFollowBlks(ppBTab,ppSrcBlk);
  PopAllFollowBlks(ppBTab,ppDstBlk);
  /*pBlock pSrcTmpBlk = pSrcBlk->next,pDstTmpBlk=pDstBlk->next;*/

  (*ppSrcBlk)->prev->next = NULL;
  (*ppSrcBlk) ->next = (*ppDstBlk)->next;
  (*ppSrcBlk)->prev = (*ppDstBlk);
  (*ppDstBlk)->next = (*ppSrcBlk);
}
static void MoveOver(pBlock *ppBTab,pBlock *ppSrcBlk, pBlock *ppDstBlk)
{
  pBlock lastDstBlk = (*ppDstBlk);
  PopAllFollowBlks(ppBTab,ppSrcBlk);
  (*ppSrcBlk)->prev->next = NULL;
  while(lastDstBlk->next != NULL)
    lastDstBlk = lastDstBlk->next;
  (*ppSrcBlk)->next = lastDstBlk->next;
  (*ppSrcBlk)->prev = lastDstBlk;
  lastDstBlk->next = (*ppSrcBlk);
}
static void PileOnto(pBlock *ppBTab,pBlock *ppSrcBlk, pBlock *ppDstBlk)
{

  PopAllFollowBlks(ppBTab,ppDstBlk);
  (*ppSrcBlk)->prev->next = NULL;
  (*ppDstBlk)->next = *ppSrcBlk;
  (*ppSrcBlk)->prev = *ppDstBlk;
}
static void PileOver(pBlock *ppBTab,pBlock *ppSrcBlk, pBlock *ppDstBlk)
{
  pBlock lastDstBlk = (*ppDstBlk);
  (*ppSrcBlk)->prev->next = NULL;
  while(lastDstBlk->next != NULL)
    lastDstBlk = lastDstBlk->next;

  (*ppSrcBlk)->prev = lastDstBlk;
  lastDstBlk->next = (*ppSrcBlk);
}   

static void PrintBlock(pBlock pBlk)
{
  pBlock tmpBlk = (pBlk) -> next;
  while(tmpBlk != NULL)
    {
      printf(" %d",tmpBlk->data);
      tmpBlk = tmpBlk -> next;
    }
  printf("\n");
}
static void PrintBlks(pBlock *ppBlk, int arraysize)
{
  int i;
  for(i = 0; i < arraysize; i++)
    {
      printf("%d:",i);
      PrintBlock(ppBlk[i]);
    }
}
      
int main(void)
{
  int n;
  pBlock *ppBlks,pSrcBlk,pDstBlk;
  char str1[10],str2[10];
  int fstBlkNum,scdBlkNum,i,j;
  int isFound1, isFound2;
  
  scanf("%d",&n);
  getchar();
  ppBlks = malloc(n * sizeof(*ppBlks));
  for(i = 0; i < n; i++)
    {
      CreateHeader(&ppBlks[i]);
      InsertOnFirst(&ppBlks[i],i);
    }
  /*  PrintBlks(ppBlks,n);*/
  while(1)
    {
      scanf("%s",str1);

      if(strcmp(str1,"quit") == 0)
	break;
      scanf("%d %s %d",&fstBlkNum,str2,&scdBlkNum);
      if(fstBlkNum == scdBlkNum)
	continue;
      for(i = 0; i < n; i++)
	{
	  isFound1 = FindBlock(&ppBlks[i],fstBlkNum,&pSrcBlk);
	  if(isFound1)
	    break;
	}
      for(j = 0; j < n; j++)
	{
	  isFound2 = FindBlock(&ppBlks[j],scdBlkNum,&pDstBlk);
	  if(isFound2)
	    break;
	}
      if(i != j && strcmp(str1,"move") == 0 && strcmp(str2,"onto") == 0)
	MoveOnto(ppBlks,&pSrcBlk,&pDstBlk);
      else if(i != j && strcmp(str1,"move") == 0 && strcmp(str2,"over") == 0)
	MoveOver(ppBlks,&pSrcBlk,&pDstBlk);
      else if(i != j && strcmp(str1,"pile") == 0 && strcmp(str2,"onto") == 0)
	PileOnto(ppBlks,&pSrcBlk,&pDstBlk);
      else if(i != j && strcmp(str1,"pile") == 0 && strcmp(str2,"over") == 0)
	PileOver(ppBlks,&pSrcBlk,&pDstBlk);
      /*      PrintBlks(ppBlks,n);*/
    }
  PrintBlks(ppBlks,n); 
  return 0;
}
 

 另外一种方案(使用栈进行操作):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MINSTACKSIZE 30
#define STACKINCREMENT 30
struct stack{
  int capacity;
  int top;
  int *array;
};
typedef struct stack Stack;

Stack *CreateStack()
{
  Stack *pStk = malloc(sizeof(*pStk));
  pStk->array = malloc(MINSTACKSIZE*sizeof(*(pStk->array)));
  if(pStk->array == NULL)
    {
      fprintf(stderr,"error:no space to allocate.\n");
      exit(EXIT_FAILURE);
    }
  else
    {
      pStk->capacity = MINSTACKSIZE;
      pStk->top = 0;
    }
  return pStk;
}

int IsStackEmpty(Stack *pStk)
{
  return pStk->top == 0;
}
int IsStackFull(Stack *pStk)
{
  return pStk->capacity == pStk->top + 1;
}
int Push(Stack *pStk, int data)
{
  if(IsStackFull(pStk))
    {
      pStk->array = realloc(pStk, (pStk->capacity+STACKINCREMENT)*
			    sizeof(*(pStk->array)));
      if(pStk->array == NULL)
	{
	  fprintf(stderr, "error: no space to allocate\n");
	  exit(EXIT_FAILURE);
	}
      else
	{
	  pStk -> capacity += STACKINCREMENT;
	}
    }
  pStk -> array[++(pStk -> top)] = data;
  return 0;
}
int Pop(Stack *pStk)
{
  if(IsStackEmpty(pStk))
    {
      fprintf(stderr,"error: empty stack can pop nothing\n");
      exit(EXIT_FAILURE);
    }
  else
    return pStk->array[(pStk -> top) --] ;
}
int Top(Stack *pStk)
{
  if(IsStackEmpty(pStk))
    {
      fprintf(stderr,"error: empty stack  don't have top element\n");
      exit(EXIT_FAILURE);
    }
  else
    return pStk->array[pStk -> top] ;
}

int Find(Stack *pStk, int data)
{
  int i;
  for(i = 1; i <= pStk->top; i++)
    if(pStk -> array[i] == data)
      break;
  if(i > pStk->top)
    return 0;
  else
    return i;
}

int PopFollowingBack(Stack **ppStkArray, int index, int pos)  
{
  Stack *pCurStk = ppStkArray[index];
  int curData;
  while(pCurStk -> top > pos)
    {
      curData = Pop(pCurStk);
      /*      pTmpStk = ppStkArray[curData];*/
      Push(ppStkArray[curData],curData);
    }
  return 0;
}
int PushCurAndFollowing(Stack **ppStkArray, int srcIndex, int srcPos, 
		     int dstIndex, int dstPos)
{
  int i,srcTop = ppStkArray[srcIndex] -> top;
  for(i = srcPos; i <= srcTop; i++)
    {
      Push(ppStkArray[dstIndex],ppStkArray[srcIndex]->array[i]);
    }
  ppStkArray[srcIndex] -> top -= srcTop - srcPos + 1;
  return 0;
}
int MoveOnto(Stack **ppStkArray,int srcIndex,int srcPos,
	     int dstIndex,int dstPos)
{
  PopFollowingBack(ppStkArray,srcIndex,srcPos);
  PopFollowingBack(ppStkArray,dstIndex,dstPos);
  PushCurAndFollowing(ppStkArray,srcIndex,srcPos,dstIndex,dstPos);
  return 0;
}
int MoveOver(Stack **ppStkArray,int srcIndex,int srcPos,
	     int dstIndex,int dstPos)
{
  PopFollowingBack(ppStkArray,srcIndex,srcPos);
  PushCurAndFollowing(ppStkArray,srcIndex,srcPos,dstIndex,dstPos);
  return 0;
}
int PileOnto(Stack **ppStkArray,int srcIndex,int srcPos,
	     int dstIndex, int dstPos)
{
  PopFollowingBack(ppStkArray,dstIndex,dstPos);
  PushCurAndFollowing(ppStkArray,srcIndex,srcPos,dstIndex,dstPos);
  return 0;
}
int PileOver(Stack **ppStkArray,int srcIndex,int srcPos,
	     int dstIndex,int dstPos)
{
  PushCurAndFollowing(ppStkArray,srcIndex,srcPos,dstIndex,dstPos);
  return 0;
}

void PrintStack(Stack *pStk)
{
  int i;
  for(i = 1; i <= pStk->top; i++)
    printf(" %d",pStk->array[i]);
  printf("\n");
}
void PrintAllBlocks(Stack **ppStk, int blockNum)
{
  int i;
  for(i = 0; i < blockNum; i++)
    {
      printf("%d:",i);
      PrintStack(ppStk[i]);
    }
}
int main(void)
{
  Stack **ppStkArray;
  int n;
  int i,j;
  char str1[10],str2[10];
  int srcData,dstData;
  int srcPos,dstPos;

  scanf("%d",&n);
  ppStkArray = malloc(n*sizeof(*ppStkArray));
  for(i = 0; i < n; i++)
    {  
      ppStkArray[i] = CreateStack();
      Push(ppStkArray[i],i);
    }
  /*  PrintAllBlocks(ppStkArray,n);

  printf("after popping %d\n",Pop(ppStkArray[2]));
  PrintAllBlocks(ppStkArray,n);*/
  while(1)
    {
      scanf("%s",str1);
      if(strcmp(str1,"quit")==0)
	break;
      scanf("%d %s %d",&srcData,str2,&dstData);
      if(srcData == dstData)
	continue;
      for(i = 0; i < n; i++)
	{
	  srcPos = Find(ppStkArray[i],srcData);
	  if(srcPos)
	  break;
	}
      for(j = 0; j < n; j++)
	{
	  dstPos = Find(ppStkArray[j],dstData);
	  if(dstPos)
	    break;
	}
      if(i == j)
	continue;
      else
	{
	  if(strcmp(str1,"move") == 0 && strcmp(str2, "onto") == 0)
	    MoveOnto(ppStkArray,i,srcPos,j,dstPos);
	  else  if(strcmp(str1,"move") == 0 && strcmp(str2, "over") == 0)
	    MoveOver(ppStkArray,i,srcPos,j,dstPos);
	  else  if(strcmp(str1,"pile") == 0 && strcmp(str2, "onto") == 0)
	    PileOnto(ppStkArray,i,srcPos,j,dstPos);
	  else  if(strcmp(str1,"pile") == 0 && strcmp(str2, "over") == 0)
	    PileOver(ppStkArray,i,srcPos,j,dstPos);
	  /*PrintAllBlocks(ppStkArray,n);*/
	}

    }
  PrintAllBlocks(ppStkArray,n);
  return 0;
}

### 关于头歌平台中序列式容器 The Blocks Problem 的解析 在头歌平台的6.1.1章节中,序列式容器被广泛用于解决一系列问题,其中6.1.1.1节中的 **The Blocks Problem** 是一个经典的例子。该问题的核心在于模拟一组堆叠的块,并根据指令对这些块进行移动操作。以下是对此问题的详细解析。 #### 问题描述 假设有一组编号从0到n-1的块,初始时每个块单独放置在一个堆栈中。程序需要支持以下两种操作: 1. `move a onto b`:将块a及其上方的所有块移除,然后将块a单独放置在块b的顶部。 2. `pile a over b`:将块a及其上方的所有块作为一个整体移动到块b所在堆栈的顶部[^1]。 #### 数据结构选择 为了高效地实现上述操作,通常使用一种基于列表的结构来表示堆栈。具体来说: - 每个堆栈可以用一个列表表示,列表中的元素按从底到顶的顺序排列。 - 使用一个字典或数组来记录每个块当前所在的堆栈索引,以便快速定位块的位置。 #### 实现逻辑 以下是解决问题的核心逻辑: 1. **初始化**:创建n个堆栈,每个堆栈包含一个块。 2. **解析命令**:读取输入命令并解析为具体的操作类型和参数。 3. **执行操作**: - 对于`move a onto b`,首先找到块a和块b所在的堆栈,移除块a及其上方的所有块,然后将块a单独放置在块b的顶部。 - 对于`pile a over b`,同样找到块a和块b所在的堆栈,但这次将块a及其上方的所有块作为一个整体移动到块b的顶部[^1]。 4. **输出结果**:根据需要输出最终的堆栈状态。 #### 示例代码 以下是用Python实现的一个简单版本: ```python def blocks_problem(n, commands): stacks = {i: [i] for i in range(n)} # 初始化堆栈 block_to_stack = {i: i for i in range(n)} # 记录每个块所在的堆栈 def move(a, b): stack_a = block_to_stack[a] stack_b = block_to_stack[b] if stack_a == stack_b: return # 移除块a及其上方的所有块 index_a = stacks[stack_a].index(a) moved_blocks = stacks[stack_a][index_a:] stacks[stack_a] = stacks[stack_a][:index_a] # 将块a单独放置在块b的顶部 stacks[stack_b].extend([a]) for block in moved_blocks: block_to_stack[block] = stack_b def pile(a, b): stack_a = block_to_stack[a] stack_b = block_to_stack[b] if stack_a == stack_b: return # 找到块a及其上方的所有块 index_a = stacks[stack_a].index(a) moved_blocks = stacks[stack_a][index_a:] stacks[stack_a] = stacks[stack_a][:index_a] # 将块a及其上方的所有块移动到块b的顶部 stacks[stack_b].extend(moved_blocks) for block in moved_blocks: block_to_stack[block] = stack_b for command in commands: if command.startswith("move"): _, a, _, b = command.split() move(int(a), int(b)) elif command.startswith("pile"): _, a, _, b = command.split() pile(int(a), int(b)) return stacks ``` #### 运行示例 假设输入如下: ```plaintext 5 move 1 onto 2 pile 3 over 1 move 4 onto 3 ``` 运行结果将是: ```python { 0: [0], 1: [1, 2, 3, 4], 2: [], 3: [], 4: [] } ``` #### 算法复杂度分析 - **时间复杂度**:对于每次操作,查找块所在堆栈的时间复杂度为O(1),而移除或添加块的操作取决于堆栈的高度,最坏情况下为O(n)。 - **空间复杂度**:需要O(n)的空间来存储堆栈和映射关系。 #### 总结 通过合理选择数据结构和算法,可以高效地解决 **The Blocks Problem**。此问题不仅考察了对序列式容器的理解,还涉及对堆栈操作的灵活运用[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值