Poj·Dessert

初见安~这里是传送门:Poj P1950

Description

John奶牛排队进餐制定了新的规定。N (3 <= N <= 15) 头奶牛不仅要按秩序站成一排,而且要每两头牛之间间隔一张标有符号"+"、"-"、或"."的餐巾纸。为了获得甜点,奶牛数字和餐巾纸上的符号组成的算式要得到结果0。标有符号"." 的餐巾纸使得奶牛能够得到更大的数字,例如以下算式:
1 - 2 . 3 - 4 . 5 + 6 . 7
它表示1-23-45+67,结果是0。你的任务是帮助奶牛获得甜点。

Input

仅一个整数N.

Output

每行一个输出前20组可行解的算术表达式。
最后一行输出解的总数。
输出顺序依照字典顺序:"+"最前,"-"其次,"."最后。
如果解的总数小于20,要么输出所有可行解表达式。

Sample Input

7

Sample Output

1 + 2 - 3 + 4 - 5 - 6 + 7
1 + 2 - 3 - 4 + 5 + 6 - 7
1 - 2 + 3 + 4 - 5 + 6 - 7
1 - 2 - 3 - 4 - 5 + 6 + 7
1 - 2 . 3 + 4 + 5 + 6 + 7
1 - 2 . 3 - 4 . 5 + 6 . 7
6

Sol

这个题和洛谷的乘积最大有点像,但是这个明显不能用dp来做了。是的——dfs暴力搜!!!

我们设现在处理到了第x个数x,要在它的后面添加符号,牵连到的就是x的前面的数值和后面的数。因为如果是‘.’的话就还要涉及到改变前面的数值。所以dfs里传值三个变量——当前x,至此的sum和前一个数值pre。pre是随当前添的符号而改变的。

+和-都比较好操作,到了‘.‘的时候就要注意一下了——要特判下一个数字是不是两位数,是的话要预留两位出来。

然后dfs直接操作就可以了。n也不大,大致返回一下就可以了。

下面是代码及详解——

#include<bits/stdc++.h>
using namespace std;
int n, tot = 0, place = 1;
char ans[100], op[3] = {'+', '-', '.'};
void dfs(int x, int pre, int sum)
{
	if(!sum && x == n)//合法解
	{
		tot++;//tot答案计数
		if(tot > 20) return;
		printf("1");
		for(int q = 2; q <= place; q++)
		{
			int r = ans[q] - '0';//不管是多少,都直接+'0'存储,方便
			if(r >= 10) printf(" %d", r);
			else printf(" %c", ans[q]);
		}
		puts("");
		return;
	}
	
	if(x == n) return;
	for(int i = 0; i < 3; i++)//三种操作
	{
		register int tsum = sum, tpre = pre;
		if(!i) sum += x + 1, pre = x + 1;//回溯后还要用,所以要先存起来
		else if(i == 1) sum -= (x + 1), pre = -(x + 1);//改变pre
		else
		{
			register int tmp;
			if(x + 1 > 9) tmp = abs(pre) * 100;//判断下一个数是不是两位数
			else tmp = abs(pre) * 10;//如果是的话就要留两位出来,也就是*100
			if(pre > 0) sum = sum - pre + tmp + x + 1, pre = tmp + x + 1;
			else sum = sum - pre - tmp - x - 1, pre = -tmp - x - 1;//注意这里还是-pre
		}
		ans[++place] = op[i];
		ans[++place] = x + 1 + '0';
		dfs(x + 1, pre, sum);
		sum = tsum, pre = tpre;
		place -= 2;//一个符号一个数字,两位回溯
	}
}
int main()
{
	scanf("%d", &n);
	ans[1] = '1';//1可以初始化
	dfs(1, 1, 1);
	printf("%d\n", tot);
	return 0;
}

迎评:)
——End——

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值