[CF71E]Nuclear Fusion

71E:Nuclear Fusion

题意简述

给你 n 个数,问能不能在全部使用的情况下拼出另一组m个数。
题目中是以化学元素给出的,你需要转换成数= =

数据范围

1n,m17

思路

不妨将状态的值表示为一个二元组 (u,v) 表示拼到了第 u 个数的v,这个二元组是全序关系的。
状态表示我们令 f[i] 表示用到的集合的二进制压缩为 j ,得到的最优值。
这样得出了状态转移方程:
f[i]=max(f[i(1<<q)]+a[i])(i&amp;(1<<q)0)
如果 f[2n1](m,0) 就无解。
时间复杂度 O(n2n)

代码

#include <cstdio>
#include <cstring>
using namespace std;
const char fuck[100][3]={"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;
int seq[20],tar[20];
char tmp[10];
int link[140000];
struct data{
    int id,val;
    data()
    {
        id=0,val=0;
    }
    data(int _id,int _val)
    {
        id=_id,val=_val;
    }
    bool operator < (const data &n1) const
    {
        return id==n1.id ? val<n1.val : id<n1.id;
    }
    bool operator == (const data &n1) const
    {
        return id==n1.id&&val==n1.val;
    }
    data operator + (const int &p) const
    {
        if (tar[id]-val<p)
            return data(-1,0);
        if (tar[id]-val==p)
            return data(id+1,0);
        if (tar[id]-val>p)
            return data(id,val+p);
    }
}f[140000];
int trans()
{
    scanf("%s",tmp);
    for (int i=0;i<100;i++)
        if (strcmp(tmp,fuck[i])==0)
            return i+1;
    return -1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<n;i++)
        seq[i]=trans();
    for (int i=0;i<m;i++)
        tar[i]=trans();
    memset(link,0xff,sizeof(link));
    int lim=(1<<n)-1;
    for (int i=0;i<=lim;i++)
        for (int j=0;j<n;j++)
            if (!(i&(1<<j)))
                if (f[i|(1<<j)]<f[i]+seq[j])
                {
                    f[i|(1<<j)]=f[i]+seq[j];
                    link[i|(1<<j)]=i;
                }
    if (f[lim]==data(m,0))
    {
        printf("YES\n");
        int now=lim,tmp=0,v=0;
        while (now)
        {
            tmp=now-link[now];
            for (int i=0;i<n;i++)
                if (tmp&(1<<i))
                    printf(v++ ? "+%s" : "%s",fuck[seq[i]-1]);
            if (!f[link[now]].val)
            {
                v=0;
                printf("->%s\n",fuck[tar[f[link[now]].id]-1]);
            }
            now=link[now];
        }
    }
    else
        printf("NO\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值