poj 1014

本文介绍了一个ACM风格的石子划分问题解决思路,通过DFS深度优先搜索算法来判断一组石子是否可以被划分为两个价值相等的部分。文章详细解释了算法步骤,包括初始化参数、设定结束条件、剪枝优化等,并提供了完整的C语言实现代码。

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

题目描述

http://poj.org/problem?id=1014

思路

1.石子总价值为奇数肯定无法划分
2.石子总价值为偶数,则划分目标为总价值一半
3.石子总数去除掉价值为0的
4.采用DFS暴搜,状态量为目标价值和石子总数
5.结束条件为目标价值为0且石子总数为0
6.只能分成两组

实测已经AC

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

typedef unsigned int   UINT32;
typedef unsigned short UINT16;
typedef unsigned char  UINT8;
typedef int   INT32;
typedef short INT16;
typedef char  INT8;
typedef void  VOID;

#define TRUE  (1)
#define FALSE (0)
#define SUCCESS (0)
#define FAIL    (1)
#define MAX_MARBLE_NUM (20005)
#define MAX_INPUT_NUM (6)

UINT32 g_inputNum[MAX_INPUT_NUM];/*输入数组*/
UINT32 g_inputIndex = 0;/*输入数组下标索引*/

UINT32 g_dividValue;/*划分价值*/
UINT32 g_value[MAX_MARBLE_NUM];/*记录输入价值数组*/
UINT32 g_valueIndex = 0;
UINT32 g_visit[MAX_MARBLE_NUM];/*记录是否访问过*/
UINT32 g_dividFlag = FALSE;/*是否能够划分*/

UINT32 g_loop = 1;/*输入组数*/

INT32 cmpfunc(const VOID * a, const VOID * b)
{
	return (*(INT32*)b - *(INT32*)a);/* 由大到小 */
}

VOID DFS(UINT32 leftValue, UINT32 leftMarbleNum)
{
	UINT32 i;
	if (leftValue == 0) {
		g_dividFlag = TRUE;
		return;
	}
	if (g_dividFlag == TRUE) {
		/*剪枝*/
		return;
	}
	if ((leftValue > 0) && (leftMarbleNum > 0)) {
		for (i = 0; i < g_valueIndex; i++) {
			if ((g_visit[i] == FALSE) && (leftValue >= g_value[i])) {
				g_visit[i] = TRUE;
				leftValue -= g_value[i];
				leftMarbleNum -= 1;
				DFS(leftValue, leftMarbleNum);
				leftValue += g_value[i];
				leftMarbleNum += 1;				
			}
		}
	}
	return;
}

UINT32 IsBreak()
{
	UINT32 i;
	for (i = 0; i < MAX_INPUT_NUM; i++) {
		if (g_inputNum[i] != 0) {
			return FALSE;
		}
	}
	return TRUE;
}


int main()
{
	INT32 i, j;
	UINT32 inputNum;
	UINT32 totalValue;
	UINT32 totalNum;

	while (scanf_s("%d", &inputNum) != EOF) {
		g_inputNum[g_inputIndex] = inputNum;
		g_inputIndex++;
		if (g_inputIndex == MAX_INPUT_NUM) {
			if (IsBreak() == TRUE) {
				break;
			}
			g_inputIndex = 0;/*数组下标归0*/
			printf("Collection #%d:\n", g_loop);
			g_loop++;/*输入数据组数+1*/
					 /* 计算总价值和总个数,总价值为奇数,肯定无法均分为两部分 */
			totalNum = 0;
			totalValue = 0;
			g_valueIndex = 0;

			for (i = MAX_INPUT_NUM - 1; i >= 0; i--) {
				if (g_inputNum[i] == 0) {
					continue;
				}
				totalNum += g_inputNum[i];
				totalValue += (g_inputNum[i] * (i + 1));
				for (j = 0; j < g_inputNum[i]; j++) {
					g_value[g_valueIndex] = (i + 1);
					g_visit[g_valueIndex] = FALSE;
					g_valueIndex++;
				}
			}

			if (totalValue % 2 != 0) {
				printf("Can't be divided.\n");
				printf("\n");
				continue;
			}
			g_dividValue = totalValue / 2;/*划分价值为总价值一半*/
			for (i = 0; i < g_valueIndex; i++) {
				if (g_value[i] > g_dividValue) {
					printf("Can't be divided.\n");
					printf("\n");
					break;
				}
			}
			g_dividFlag = FALSE;
			DFS(g_dividValue, totalNum);
			if (g_dividFlag == TRUE) {
				printf("Can be divided.\n");
				printf("\n");
			}
			else {
				printf("Can't be divided.\n");
				printf("\n");
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值