POJ1416 切割纸条(DFS+剪枝)


这题目个人感觉有点难,很难抽象出具体的搜索模型,看了别人的解题报告才有思路。

切割一个数据即切割纸条,相加的和最接近给出目标的值。
比如,12346是数据,target的值是50,应该把数字切成四部分,分别是1、2、34、6。因为这样所得到的和43 (= 1 + 2 + 34 + 6) 
是所有可能中最接近而不超过50的。碎纸还有以下三个要求:
1、如果target的值等于纸条上的值,则不能切。
2、如果没有办法把纸条上的数字切成小于target,则输出error。如target是1而纸条上的数字是123,则无论你如何切得到的和都比1大。
3、如果有超过一种以上的切法得到最佳值,则输出rejected。如target为15,纸条上的数字是111,则有以下两种切法11、1或者1、

 2140K 32MS C++ 2636B 2013-12-05 18:14:25


下面是代码:


#include
#include
#include
#include 
#include 
#include 
#include 
#include 
using namespace std;

#include 
#include 
#include 


#define N   12

char g_page[N] = {};
int g_target = 0;
int g_min = INT_MAX;
int g_mway = 0;
short g_flag[1000000] = {};

int getNum(int iSt, int iLen, const char *inSz)
{
	char szInt[N];
	memset(szInt, 0, sizeof(szInt));

	for(int i = iSt; i < iSt+iLen; i++)
	{
		szInt[i-iSt] = inSz[i];
	}

	return atoi(szInt);
}

int getSub(int iSt, const char *inSz, char *outSz)
{
	for(int i = iSt; inSz[i]; i++)
	{
		outSz[i-iSt] = inSz[i];
	}

	return atoi(outSz);
}

void dfs(const char *szInt, int iSum, int iCen) 
{
	int iLen = strlen(szInt);

	for(int i = 1; i <= iLen; i++)
	{
		int iTemp = getNum(0, i, szInt);

		if(iSum+iTemp > g_target)
		{
			continue;
		}

		char szTmep[N];
		memset(szTmep, 0, sizeof(szTmep));
		getSub(i, szInt, szTmep);

		if(i == iLen)
		{
			if(g_min >= abs(iSum+iTemp - g_target))
			{
				g_min = abs(iSum+iTemp - g_target);
				g_mway = iCen;

				g_flag[g_min]++;
				//printf("%d %d\n", iSum+iTemp, g_mway);
			}
			continue;
		}

		dfs(szTmep, iSum + iTemp, iCen*10+i);
	}
	
	return ;
}

void printWay()
{
	char szTemp[N];

	//itoa(g_mway, szTemp, 10); // 不是C标准库的函数

	sprintf(szTemp,"%d",g_mway);

	int iPos = 0;
	int iLen = strlen(szTemp);

	for(int i = 0; i < iLen && g_mway > 0; i++)
	{
		int iTemp = int(szTemp[i] - '0');

		while(iTemp--)
		{
			printf("%c", g_page[iPos++]);
		}

		printf(" ");
	}

	while(g_page[iPos])
	{
		printf("%c", g_page[iPos++]);
	}

	printf("\n");
}

int getMin()
{
	int iSum = 0;
	int iLen = strlen(g_page);

	for(int i = 0; i < iLen; i++)
	{
		iSum += int(g_page[i] - '0');
	}

	return iSum;
}

int main()
{
	//int take = ::GetTickCount();
    //freopen("out47.txt", "w", stdout);

	while(true)
	{
		scanf("%d %s", &g_target, g_page);

		if(0 == g_target)
		{
			break;
		}

		memset(g_flag, 0, sizeof(g_flag));
		g_min = INT_MAX;
		g_mway = 0;

		if(getMin() > g_target)
		{
			printf("error\n");
		}
		else
		{
			dfs(g_page, 0, 0);

			if(g_flag[g_min] > 1)
			{
				printf("rejected\n");
			}
			else
			{
				printf("%d ", g_target-g_min);
				printWay();
			}
		}
		
		//printf("g_min=%d g_mway=%d\n", g_target-g_min, g_mway);
	}
	//cout<<::GetTickCount() - take<


你可能感兴趣的:(ACM)