• NOIp2004 虫食算(搜索剪枝)


    洛谷P1092虫食算

    题意:

    N进制加法,三个数都是N位,计算出使式子成立的每个字母分别所代表的值.((N<=26))

    如图是N=4的一个例子,当ABCD分别代表0123时,式子成立.

    本题的正解应该是高斯消元,但搜索+剪枝足够应付过去.

    直接搜索,枚举每一个字母分别代表的值,这样显然会超时,考虑如何剪枝.

    剪枝1:题目中说了三个数都是N位,说明最高位没有进位.

    (假设A,B分别是两个加数的最高位)
         则当A+B>=N时,不成立;
    

    剪枝2:因为是加法运算,所以最多进1.

    (假设A,B,C是一一对应的任一位上)
         则当(A+B)%N!=C&&(A+B+1)%N!=C时,不成立;
         
    
    int n,order;
    int used[30],num[30],nxt[30];
    int a[30],b[30],c[30];
    char s1[30],s2[30],s3[30];
    void NEXT(int x){
        if(used[x])return;
        used[x]=1;
        nxt[order++]=x;
        return;
    }
    inline bool jz(){//剪枝
        if(num[a[0]]+num[b[0]]>=n)return true;
    //对应剪枝二
        for(int i=n-1;i>=0;i--){
    		int A=num[a[i]];
    		int B=num[b[i]];
            int C=num[c[i]];
    		if(A==-1||B==-1||C==-1)continue;
    		if((A+B)%n!=C&&(A+B+1)%n!=C)
            	return true;
        }
    //对应剪枝一
        return false;
    }
    inline bool cheek(){//检验式子是否成立
        for(int i=n-1,x=0;i>=0;i--){
    		int A=num[a[i]];
            int B=num[b[i]];
            int C=num[c[i]];
    		if((A+B+x)%n!=C)return false;
    		x=(A+B+x)/n;
        }
    //x表示进位
        return true;
    }
    void print(){//输出
        for(int i=0;i<n;i++)
    		printf("%d ",num[i]);
        exit(0);
    }
    inline void dfs(int x){
        if(jz()==true)return;
        if(x==n){
    		if(cheek()==true)print();
    		return;
        }
        for(int i=n-1;i>=0;i--){
    		if(used[i]==1)continue;
    		used[i]=1;
    		num[nxt[x]]=i;
    		dfs(x+1);
    		used[i]=0;
    		num[nxt[x]]=-1;
        }
    }
    int main(){
        n=read();
        scanf("%s%s%s",s1,s2,s3);
        for(int i=0;i<n;i++){
        	a[i]=s1[i]-'A';
            b[i]=s2[i]-'A';
            c[i]=s3[i]-'A';
        }
    //将三个字符串转为整型数字分别存入三个数组中
        for(int i=n-1;i>=0;i--){
        	NEXT(a[i]);
            NEXT(b[i]);
            NEXT(c[i]);
        }
    //next[x]表示整个式子从上到下,从右到左(从低位到高位)
    //每个字母(已经转换为了数字)出现的顺序
    //这也是我们搜索时赋值的顺序,即从低位到高位,便于处理
        memset(num,-1,sizeof(num));
        memset(used,0,sizeof(used));
        dfs(0);
        return 0;
    }
    
    
  • 相关阅读:
    css 如何让背景图片拉伸填充避免重复显示
    CDHtmlDialog 基本使用
    RES协议
    Sata win7 热插拔(AHCI)
    __argc和__argv变量
    MFC进度条刷新处理
    SVN强制注释
    自动build服务器 CruiseControl.NET
    opencv Mat 像素操作
    std::string 用法
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10324283.html
Copyright © 2020-2023  润新知