初见安~这里是传送门: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——