【2019.7.20 NOIP模拟赛 T1】A(A)(暴搜)

打表+暴搜

这道题目,显然是需要打表的,不过打表的方式可以有很多。

我是打了两个表,分别表示每个数字所需的火柴棒根数以及从一个数字到另一个数字,除了需要去除或加入的火柴棒外,至少需要几根火柴棒

然后我们就可以暴搜了,大体就是枚举等式左边两个数每一位的值,并枚举中间的运算符是\(+\)还是\(-\),然后计算出等式右边的值,判断是否合法。

中间过程可以加上一些剪枝。

注意当火柴棒从某一位移到另一位时,我们可以规定,去除火柴棒需要算步数,加入火柴棒则无需算步数,这样就可以避免重复了。

具体实现有一些小细节,可以参考代码

代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 20
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
const int q[10]={6,2,5,5,4,5,6,3,7,6};//打表
const int p[10][10]=//打表
{
    {0,0,1,1,1,1,1,0,0,1},{0,0,1,0,0,1,1,0,0,0},{1,1,0,1,2,2,1,1,0,1},{1,0,1,0,1,1,1,0,0,0},{1,0,2,1,0,1,1,1,0,0},
    {1,1,2,1,1,0,0,1,0,0},{1,1,1,1,1,0,0,1,0,1},{0,0,1,0,1,1,1,0,0,0},{0,0,0,0,0,0,0,0,0,0},{1,0,1,0,0,0,1,0,0,0}
};
int n,a[N+5],b[N+5];string s;
class Dfser//暴搜
{
    private:
        int ans;
        I void Calc(CI x,CI y,RI v,CI w)//计算,判断答案是否合法
        {
            if(w<0) return;RI i,t,k=0,t1=0,t2=0;for(i=x;i^n;++i) t1+=b[i];
            t=w;W(t2+=q[t%10],++k,t/=10);if(k>n-x||(t1+y)^t2) return;
            for(t=w,i=n-1;i>=x;--i)
            {
                if(i^(n-1)&&!t) return;
                v+=p[a[i]][t%10]+max(b[i]-q[t%10],0),t/=10;
            }Gmin(ans,v);
        }
        I void dfs(CI x,CI y,CI v,CI sv,CI op,CI tot)//暴搜,枚举每一位的值和运算符
        {
            if(abs(y)>5*(n-x)||ans<=v) return;if(s[x]=='=') return Calc(x+1,y,v,tot+sv*op);
            if(s[x]=='+') dfs(x+1,y,v,0,1,tot+sv*op),dfs(x+1,y+1,v+1,0,-1,tot+sv*op);
            else if(s[x]=='-') dfs(x+1,y,v,0,-1,tot+sv*op),dfs(x+1,y-1,v,0,1,tot+sv*op);
            else
            {
                dfs(x+1,y,v,sv*10+a[x],op,tot);
                for(RI i=!((x&&isdigit(s[x-1]))||!isdigit(s[x+1]));i<=9;++i)
                    a[x]^i&&(dfs(x+1,y+b[x]-q[i],v+p[a[x]][i]+max(b[x]-q[i],0),sv*10+i,op,tot),0);
            }
        }
    public:
        I void Solve() {ans=1e9,dfs(0,0,0,0,1,0),ans==1e9?puts("-1"):printf("%d",ans);}
}D;
int main()
{
    freopen("A.in","r",stdin),freopen("A.out","w",stdout);
    cin>>s,n=s.length(),s+="@";for(RI i=0;i^n;++i) b[i]=q[a[i]=s[i]&15];
    return D.Solve(),0;
}

转载于:https://www.cnblogs.com/chenxiaoran666/p/Contest20190720T1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值