UVA 10317 - Equating Equations (背包)

本文介绍了一种算法,用于解决给定包含加减运算符的伪等式时如何通过重新排列等式中的数字来构造正确的等式的问题。该算法首先解析输入等式,确定运算符的位置及数字的值,并计算等式的总和。之后采用动态规划方法寻找能够使等式成立的有效数字排列方案。

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

Problem F

Equating Equations

Input:standard input

Output:standard output

Time Limit:6seconds

Memory Limit:32 MB

Read equations with up to16terms and+andoperators (not unary) and reorder the terms (but not the operators) so that the equations hold. For example

 
 1 + 2 = 4 - 5 + 6

is not a correct equation but the terms can be rearranged thus so it is:

 
 6 + 2 = 4 - 1 + 5

Input

Standard input consists of several pseudo-equations, one per line. Each pseudo-equation has up to16integer terms and each term is less than100. Adjacent terms are separated by one operator, and spaces always appear surrounding the terms. There is exactly one = operator in the equation

Output

Your output will consist of one line per input line, with the same operators and the same terms. The order of the operators must be preserved, but the terms can be reordered so the equation holds. Any ordering such that the equation holds is correct. If there is more than one ordering any one of the orderings will do. If no ordering exists, a line containing

 no solution

should be printed. One space should appear on either side of each operator and there should be no other spaces.

Sample Input

1 + 2 = 4 - 5 + 6
1 + 5 = 6 + 7

Sample Output

6 + 2 = 4 - 1 + 5
no solution

(The Decider Contest, Source: Waterloo ACM Programming Contest)

题意:给一个式子,符号位置不能变,数字位置可以变,求转换成正确等式。

思路:由于只有加减,所以左边减号相当于右边加号,右边加号相当于左边减号,如此一来左右两边相等,为sum/ 2,然后去背包求sum / 2的组成方法,然后按加减输出即可。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int N = 20;

int num[N], numn, opern, Min, sum, jian, jia, jianz, jiaz, dp[N][N * 100], path[N][N * 100][N], pathn[N][N * 100], path2[N], pathn2, vis[105];;
char oper[N], c, str[105];

void init() {
    int Num = 0, flag = 0;
    numn = opern = Min = sum = jian = jia = jianz = jiaz = 0;
    for (int i = 0; i <= strlen(str); i ++) {
	if (str[i] == '+' || str[i] == '=' || str[i] == '-') {
	    if (str[i] == '+') {
		jiaz ++;
		jia ++;
	    }
	    if (str[i] == '-') {
		jian ++;
		jianz ++;
	    }
	    if (str[i] == '=') {
		jia = 0;
		jian = 0;
	    }
	    oper[opern++] = str[i];
	}
	else if (str[i] >= '0' && str[i] <= '9') {
	    Num = Num * 10 + (str[i] - '0');
	    flag = 0;
	}
	else {
	    if (flag == 0) {
		num[numn++] = Num;
		sum += Num;
		Num = 0;
		flag = 1;
	    }
	}
    }
    Min = jiaz - jia + jian + 1;
}

void DP() {
    memset(dp, 0, sizeof(dp));
    memset(pathn, 0, sizeof(pathn));
    dp[0][0] = 1;
    for (int k = 0; k < numn; k ++) {
	for (int i = Min; i >= 1; i --) {
	    for (int j = sum; j >= num[k]; j --) {
		if (dp[i - 1][j - num[k]] == 1) {
		    dp[i][j] = 1;
		    for (int l = 0; l < i - 1; l ++)
		    path[i][j][l] = path[i - 1][j - num[k]][l];
		    path[i][j][i - 1] = num[k]; pathn[i][j] = i;
		}
	    }
	}
    }
}

void print() {
    pathn2 = 0;
    memset(vis, 0, sizeof(vis));
    for (int i = 0; i < numn; i ++)
	vis[num[i]] ++;
    for (int i = 0; i < pathn[Min][sum]; i ++) {
	vis[path[Min][sum][i]] --;
    }
    for (int i = 0; i < numn; i ++) {
	if (vis[num[i]]) {
	    path2[pathn2++] = num[i];
	    vis[num[i]] --;
	}
    }
    printf("%d", path[Min][sum][0]);
    int flag = 0; int s1 = 1, s2 = 0;
    for (int i = 0; i < opern; i ++) {
	char c = oper[i];
	if (flag == 0) {
	    if (c == '+')
		printf(" %c %d", c, path[Min][sum][s1++]);
	    if (c == '-')
		printf(" %c %d", c, path2[s2++]);
	    if (c == '=') {
		flag = 1;
		printf(" %c %d", c, path2[s2++]);
	    }
	}
	else {
	    if (c == '+')
		printf(" %c %d", c, path2[s2++]);
	    if (c == '-')
		printf(" %c %d", c, path[Min][sum][s1++]);
	}
    }
    printf("\n");
}

int main() {
    while (gets(str) != NULL) {
	init();
	if (sum % 2) printf("no solution\n");
	else {
	    sum /= 2;
	    DP();
	    if (dp[Min][sum])
		print();
	    else printf("no solution\n");
	}
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值