sicily 1050 深度优先搜索解题

1050. Numbers & Letters

Constraints

Time Limit: 3 secs, Memory Limit: 32 MB

Description

In the early 80’s, a popular TV show on Dutch television was ‘Cijfers en Letters’ (Numbers and Letters). This game consisted of two game elements, in which the main goal was to outclass your opponent. Letters is a game in which you are given a number of letters with which you should form the longest Dutch word possible. Since Dutch is a very hard language to learn we will postpone implementation of this game element until after the contest. 
For the second game element ‘Numbers’ 5 different numbers are chosen, together with a target number. The aim is to use some arithmetic on (some of) the five numbers to form the target number. Each number can be used only once. It might not be possible to form the target number given the input numbers, in that case the largest number smaller than the target number that can be calculated should be given. The only mathematical operations allowed are: +, -, *, /.  All intermediate results should be integers, so division is not always allowed (e.g. (2*2)/4 is OK, but 2*(2/4) is not). 
Examples: 
- If the 5 numbers are 1, 2, 3, 7 and 100 and the target number is 573, the target number can be reached as follows: (((100-1)*2)-7)*3. -If the 5 numbers are 3, 26, 78, 12 and 17, and the target number is 30, the target number can be reached as follows: (78*3)-(12*17). 
- If the 5 numbers are 67, 69, 58, 22, 2, and the target number is 929, the target number cannot be reached, but the largest number smaller than the target number that can be reached is 923 = (22-(67-58))*(69+2). 
Your assignment is to write a program that calculates the best approximation from below of the target number using arithmetic on the 5 given numbers. Note that if it is not possible to reach the exact number, you should give the largest reachable number below the target number.

Input

The first line contains the number of runs, N. The next N lines consist of six numbers separated by a space. The first 5 numbers Mi, 1≤Mi≤100, are the numbers you can use to calculate the target number. The sixth number is the target number T, 0≤T≤1000.

Output

The output consists of N rows, each containing the best approximation of the target number using the 5 given numbers.

Sample Input

3
1 2 3 7 100 573
3 26 78 12 17 30
67 69 58 22 2 929

Sample Output

573
30 
923

#include <iostream>
using namespace std;

int target;
int a[5];
int max_r;

/*
  本题的思路为每次在5个数中选择2个数,然后对其分别进行加减乘除运算,
  在进行了每种运算之后,得到一个数,用这个数覆盖掉所选的2个数中
  的其中一个,由于等下的深度优先搜索的数组大小减一,且需扫描可用的数来确定最大数
  或者是否达到目标数,所以该其中一个为i,而不能是j,因为如果是j的话,会出现n-1的情况
  使得该运算结果等下不可用的情况。 
  另外一个数用当前数组最后一个数覆盖,使数的个数减一
  然后进行深度优先搜寻,构建深度优先搜索树,继续进行以上运算直到计算得到目标数,或者
  只剩下一个数不能继续进行运算为止 
 */ 
void DFS(int n) { 
	//扫描当前可用数组,其中包含上一步骤的运算结果在内
	//确定当前数组最大数 
	for (int i = 0; i < n; i++) {
		if (a[i] <= target && a[i] > max_r) {
			max_r = a[i];
			
		}
	}
	//如果达到了目标数,直接返回 
	if (max_r == target) {
			return;
	}
	//如果数组大小为1,不能继续进行运算了,此时max_r等于该5个数进行运算
	//得到的小于目标数的最大数 
	if (n == 1) {
		return;
	}
	//从n个数中任意选择两个数进行4种运算,其中通过两重循环,包含了所有可能的两个数的情况 
	for (int i = 0; i < n; i++) {
		for (int j = i+1; j < n; j++) {
			
			int a1 = a[i];
			int a2 = a[j];
			//覆盖掉已经选择了的两个数i,j,从而继续对其他数(包括刚刚计算得到的运算结果)
			//进行深度优先搜索 
			a[j] = a[n-1];
			
			a[i] = a1 + a2;
			DFS(n-1);
			
			a[i] = a1 - a2;
			DFS(n-1);
			a[i] = a2 - a1;
			DFS(n-1);
			
			a[i] = a1 * a2;
			DFS(n-1);
			
			if (a2 != 0 && a1 % a2 == 0) {
				a[i] = a1 / a2;
			} else if (a1 != 0 && a2 % a1 == 0) {
				a[i] = a2 / a1;
			}
			DFS(n-1);
			
			//运算完后,使得i,j变回原来的数,以便进行下一轮循环 
			a[i] = a1;
			a[j] = a2;
		}
	}
} 

int main() {
	int test;
	cin >> test;
	while (test-- > 0) {
		int value;
		for (int i = 0; i < 5; i++) {
			cin >> value;
			a[i] = value;
		}
		cin >> target;
		max_r = -100000000;
		DFS(5);
		cout << max_r << endl;
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/xieyizun-sysu-programmer/p/4008077.html