题解 CF71E 【Nuclear Fusion】
本题题意为: 求一组数能不能其中几个相加得出另一组数。
发现数据很小,于是想到状压。
然后dfs枚举状态。 一开始用打表的方法把原子符号变为数字。dfs(tot,sum,q)表示目前完成了tot个原子,目前原子序数累加的和,用q来表示a数组各元素取或不取。枚举原子a[i]。如果没有取过,就dfs取这个原子。
加个记忆化,比dp跑得快多了 code:
#include<bits/stdc++.h>
using namespace std;
const int N=25;
string names[] = {" ","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,k,flag;
int a[N],b[N];
bool f[105][140000];
vector<int> ans;
int getid(string x) {
for(int i=1;i<=100;i++)
if(names[i]== x) return i;
}
string getst(int i) {
return names[i];
}
void mprint(){
int sum=0,j=0;
for(int i=0;i<ans.size();i++){
sum+=ans[i];
cout<<getst(ans[i]);
if(sum==b[j]){
printf("->");
cout<<getst(b[j++]);
printf("\n");
sum=0;
}
else printf("+");
}
}
void dfs(int tot,int sum,int q){
if(sum==b[tot]){
if(tot==k) {
flag=1;
printf("YES\n");
mprint();
}
else dfs(tot+1,0,q);//下一个
}
if(sum>b[tot]) return;//减枝
if(f[tot][q]) return;//记忆化
for(int i=0;i<n&&(!flag);i++){
if(q&(1<<i)) continue;
else {
ans.push_back(a[i]);
dfs(tot,sum+a[i],q|(1<<i));
ans.pop_back();//回溯
}
}
f[tot][q]=1;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
string s;cin>>s;
a[i]=getid(s);
}
for(int i=0;i<k;i++){
string s;cin>>s;
b[i]=getid(s);
}
dfs(0,0,0);
if(!flag) printf("NO");
return 0;
}