UESTC Training for Search Algorithm——F

Nuclear Fusion

Description

We have a reactor contains a set of N atoms of some chemical elements.
You are allowed to take any two different atoms and fuse a new one from them. That results in a new atom, whose number( its number in the periodic table of the chemical elements) is equal to the sum of the numbers of original atoms. The fusion operation can be performed several times.
We want to get M new atoms by fusing atoms we have. It is not allowed to split an atom into several atoms. All the N atoms must be used. Please find out whether it is possible.

Input

There are multiple test cases in the input.
For each test case, the first line of each test case contains two integers N and M, indicating the number of atoms we have and the number of atoms we want to get.(1<=N,M<=17)
The second line contains space-separated symbols of elements of N atoms. The third line contains space-separated symbols of elements of M atoms which need to be the result of the fusion. These atoms can be the same.

Output

If the task can be solved, print ”YES” in a single line, else print “NO”.

Sample Input

10 3
Mn Co Li Mg C P F Zn Sc K
Sn Pt Y
2 1
H H
He
2 2
Bk Fm
Cf Es

Sample Output

YES
YES
NO

Hint

The first task can be solved because
Mn+C+K->Sn
Co+Zn+Sc->Pt
Li+Mg+P+F->Y

The first 100 atoms in the periodic table of the chemical elements:
"H","He","Li","Be","B","C","N","O","F","Ne",
"Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca",
"Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu",
"Zn","Ga","Ge","As","Se","Br","Kr","Rb","Sr",
"Y","Zr","Nb","Mo","Tc","Ru","Rh","Pd","Ag",
"Cd","In","Sn","Sb","Te","I","Xe","Cs","Ba",
"La","Ce","Pr","Nd","Pm","Sm","Eu","Gd",
"Tb","Dy","Ho","Er","Tm","Yb","Lu","Hf","Ta",
"W","Re","Os","Ir","Pt","Au","Hg","Tl","Pb",
"Bi","Po","At","Rn","Fr","Ra","Ac","Th","Pa",
"U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm"
All the atoms appear in this problem are in the table above.

Source

CODEFORCES BETA ROUND #65 (DIV. 2)

 

/*算法思想:
  我用的DFS,先把给的元素的序号保存在a数组中,再把要得到的元素的序号保存在b数组中
  然后把这两个数组从大到小排序,主要有三个剪枝:
  剪枝1:a数组的总和和b数组的总和不等,无需BFS即可判断肯定无解
  剪枝2:每当搜索b中一个新的元素的时候,要是a中没有被用过序号最大的元素比b中的大,无解
  剪枝3:要是a[i]不能用来合成b[k],后面的和a[i]相同的也不能用来合成b[k]
*/

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
char s[110][5]=  //记录每个元素及他们的序号
{
"H","He","Li","Be","B","C","N","O","F","Ne",
"Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca",
"Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu",
"Zn","Ga","Ge","As","Se","Br","Kr","Rb","Sr",
"Y","Zr","Nb","Mo","Tc","Ru","Rh","Pd","Ag",
"Cd","In","Sn","Sb","Te","I","Xe","Cs","Ba",
"La","Ce","Pr","Nd","Pm","Sm","Eu","Gd",
"Tb","Dy","Ho","Er","Tm","Yb","Lu","Hf","Ta",
"W","Re","Os","Ir","Pt","Au","Hg","Tl","Pb",
"Bi","Po","At","Rn","Fr","Ra","Ac","Th","Pa",
"U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm"
};
int n,m,sum,tot,a[20],b[20];//a[]:表示初始的原子集合,b[]:表示目标原子集合(存的是他们对应的序号)
bool fg[20];  //判断原子是否已经用过
int find(char ch[])  //找元素对应的序号
{
    for(int j=0;j<100;j++)
        if(strcmp(s[j],ch)==0)
            return j+1;
}
bool cmp(int a,int b)  //用于排序的比较函数
{
    return a>b;
}
bool dfs(int v,int k,int left)  //a[],b[]中的起始点: v ,k ,还剩left凑够 b[k];
{
    if(left==0)  //已经凑够 b[k]
    {
        if(k==m-1) return true;  //如果已经合成了b[]中所有的原子
        int i=0;
        for(;i<n;i++)
            if(!fg[i]) break;  //找到第一个没有用于合并的原子
        if(a[i]>b[k+1]) return false;  //如果 a[]中最大的没有用的比 b 中最大的没有找到的大,肯定无解
        return dfs(i,k+1,b[k+1]);
    }
    for(int i=v;i<n;i++)
        if(!fg[i] && a[i]<=left)
        {
            fg[i]=true;
            if(dfs(i+1,k,left-a[i])) return true;
            fg[i]=false;
            while(a[i]==a[i+1] && i<n) i++;  //后面和 a[i] 相同的也不能满足
        }
    return false;
}
int main()
{
    char ch[5];
	while(scanf("%d%d",&n,&m)!=EOF)
	{
	    sum=0;
		for(int i=0;i<n;i++)
		{
			scanf("%s",ch);
			a[i]=find(ch);
			sum+=a[i];
		}  //得到a[]数组
		tot=0;
		for(int i=0;i<m;i++)
		{
			scanf("%s",ch);
			b[i]=find(ch);
			tot+=b[i];
		}  //得到b[]数组
		sort(a,a+n,cmp);  //将a数组从大到小排序
		sort(b,b+m,cmp);  //将b数组从大到小排序
		if(tot!=sum)  //如果a数组元素的序号的总和和b数组元素的序号的总和不等,肯定无解
		{
			printf("NO/n");
			continue;
		}
        memset(fg,0,sizeof(fg));
        if(dfs(0,0,b[0])) printf("YES\n");
        else printf("NO\n");
	}
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值