SOJ 1107. Simple Puzzle

Constraints

Time Limit: 10 secs, Memory Limit: 32 MB

Description

Here is a simple puzzle on numbers.

There are n numbers, each of which is of k (k$ \ge$n) distinct and significant digits. When the numbers are lined up inn rows keeping the digits in k columns, the n digits that appear in each column are also distinct. The sum of the numbers is known to beS.

One digit from each number is removed so that not more than one digit is removed from each column. The digits removed are all distinct. Thusn incomplete numbers are formed with remaining digits keeping digits in the original order. Given the incomplete numbers and the sumS, what are the original numbers?

Can you write a program that solves the simple puzzle? The program should find all possible solutions.

Input

Input consists of multiple test cases.
For each test case data is given in one line. The line contains the case number c, the given incomplete numbers followed by the sum S. A space separates two consecutive fields in input.
Input terminates with an input 0 for the case number c.

Output

For each test case, display output in one or more lines. Each line contains the case numberc and a possible solution. A solution consists of the original numbers in the order in which the incomplete numbers appear in input. If there are more than one solution, first output the one with the smallest first number. If there is a tie, first output the one with the smallest second number and so on.
In case it is not possible to solve the puzzle, assume the solution to be 0 and display output accordingly.

Sample Input

1 6 8 174
2 53 81 817
3 3 4 130
0

Sample Output

1 0
2 536 281
3 36 94
3 83 47


题意:
给出 n 个数,每个数有 k 个数字,现在把这 n 个数写成 n 行,并且对齐成 k
在每个数中擦去一个数字,并且擦去的数字的列要不相同,得到 n 个不完整的数
现在给出这 n 个不完整的数和初始 n 个数的和,求这个 n 个数
限制:
1<=n<=k<=10 (题目隐含的限制)

解法:深搜枚举,不过要注意前缀0以及数字不能重复使用



#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>

using namespace std;

struct p{
	int n1,n2;
};//保存满足条件的一对数 
bool cmp(p t1,p t2){
	return t1.n1<t2.n1;
}//用来给sort 
p res[1000];//保存所有可能的结果 
bool n1[11]; //记录第一个数的数字 
bool n2[11]; //记录第二个数的数字 

string s1,s2;
int sum,len1,len2;
int base;//有多少结果 
void two(int k,int pos){
	int num=0;
	int tmp_num;
	for(int i=0; i < len2; ++i){
		num=num*10+(s2[i]-'0');
		for(int j=0; j <= 9; ++j){
			if(len2-1-i!=pos&&n2[j]==0){
				n2[j]=1;
				tmp_num=num*10+j;
				for(int j=i+1; j < len1; ++j)
					tmp_num=tmp_num*10+(s1[i]-'0');
				//cout << k << " " << tmp_num << endl;
				if(tmp_num+k==sum){//满足结果,保存下来 
					res[base].n1=k;
					res[base].n2=tmp_num;
					base++;
				}
				n2[j]=0;
			}
		}
	}
	if(pos!=len2){//保证不重复 
		for(int i=1; i <= 9; ++i){
			if(n2[i]==1)continue;//重复了 
			//cout << k << " " << i*pow(10,len2)+num << endl;
			n2[i]=1;
			if(i*pow(10,len2)+num+k==sum){
				res[base].n1=k;
				res[base].n2=i*pow(10,len2)+num;
				base++;
			}
			n2[i]=0;
		}//加在第二个数的开头 
	}
}
void one(){
	int num=0;
	int tmp_num;
	for(int i=0; i < len1; ++i){
		num=num*10+(s1[i]-'0');
		for(int j=0; j <= 9; ++j){
			if(n1[j]==1)continue;
			n1[j]=1;
			tmp_num=num*10+j;
			for(int j=i+1; j < len1; ++j)
				tmp_num=tmp_num*10+(s1[i]-'0');
			if(tmp_num<=sum)two(tmp_num,len1-1-i); 
			n1[j]=0;
		}	
	}//加在第一个数中每个数字的后面 
	for(int i=1; i <= 9; ++i){
		if(n1[i]==1)continue;//重复了 
		n1[i]=1;
		two(i*pow(10,len1)+num,len1);
		n1[i]=0;
	}//加在第一个数的开头 
}//找到合适的第一个数然后级调用two去找第二个数 

int main()
{
	int c;
	while(cin >> c&&c){
		bool check=false;
		base=0;
		cin >> s1 >> s2 >> sum;
		len1=s1.length();
		len2=s2.length();
		memset(n1,0,sizeof(n1));
		memset(n2,0,sizeof(n2));
		for(int i=0; i < len1; ++i){
			if(n1[s1[i]-'0']) {
				check=true;
				break;
			}
			else{
				n1[s1[i]-'0']=1;
			}
		}
		for(int i=0; i < len2; ++i){
			if(n2[s2[i]-'0']) {
				check=true;
				break;
			}
			else{
				n2[s2[i]-'0']=1;
			}
		}
		//检查输入是否有重复 
		one();
		if(base==0||check) cout << c << " 0" << endl;//没答案或者输入有重复都是不合法的 
		else{
			sort(res,res+base,cmp);
			for(int i=0; i < base; ++i){
				int dig_n1=0,dig_n2=0,k1=res[i].n1,k2=res[i].n2;\
				while(k1!=0){
					dig_n1++;
					k1/=10;
				} 
				while(k2!=0){
					dig_n2++;
					k2/=10;
				}
				//检查是否有前缀0 
				cout << c << " " ;
				if(dig_n1 > len1) cout << res[i].n1;
				else cout << "0" << res[i].n1;
				if(dig_n2 > len2) cout << " " << res[i].n2 << endl;
				else cout << " 0" << res[i].n2 << endl;
			}
		} 
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值