zoukankan      html  css  js  c++  java
  • NOIP2004 虫食算

    题目传送门

    暴搜都打不对 QAQ 调了好久


    40pts

    显而易见,我们可以通过枚举全排列来找到一种合法的答案

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,ans[27];
    string ss[4];
    bool vis[27];
    long long int k[4];
    int main(){
        cin>>n;
        cin>>ss[1]>>ss[2]>>ss[3];
        for(int i=1;i<=n;i++)
          ans[i]=i-1;
    
        do{
            for(int i=1;i<=3;i++){
                k[i]=0;
                for(int j=0;j<n;j++)
                  k[i]=k[i]*n+ans[ss[i][j]-'A'+1];
            }
            if(k[1]+k[2]==k[3]){
                for(int i=1;i<=n;i++)
                  cout<<ans[i]<<" ";
                return 0;
            }
        }
        while(next_permutation(ans+1,ans+n+1));
        return 0;
    }
    

    这么暴力当然是行不通的,暴力也要暴力的优雅一些,使用(next{-}permutation)枚举全排列会难以剪枝,不如暴搜,而这道题目暴搜是可以过的(然而官方正解是高斯消元)

    AC

    高斯消元 暴搜+剪枝

    剪枝:

    1. 搜索顺序从后向前,从上到下
    2. 搜索时要判断一下当前的算式是否合法
      别的……好像也没有什么了……
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    string add[4];
    int a[21],b[21],c[21],num[110],n;
    bool vis[21];
    void judge(){  //搜出答案后判断是否合法
        bool flag=0,f=0;
        for(int i=n-1;i!=-1;i--){
            int x=(num[add[1][i]]+num[add[2][i]]+(int)flag)%n;
            if(x!=num[add[3][i]]){
                f=1; break;
            }
            flag=(num[add[1][i]]+num[add[2][i]]+(int)flag)/(n);
        }
        if(f) return ;
        else{
            for(int i='A';i<='A'+n-1;i++) printf("%d ",num[i]);
            exit(0);
        }
    }
    void dfs(int pos,int y,bool zzz){  //pos是第几列,y是第几行,zzz是当前是否要进位
        if(pos<0){
            judge(); return ;
        }
        bool flag=0;
        if(y==3){  //如果来到了答案行,直接根据答案行上方两个数+进位推出答案
        	if(num[add[y][pos]]==-1)
    	    	for(int i=0;i<=n-1;i++){
    	    		if(!vis[i]&&(num[add[1][pos]]+num[add[2][pos]]+zzz)%n==i){
    	    			vis[i]=1; num[add[y][pos]]=i;
    	    			dfs(pos-1,1,(num[add[1][pos]]+num[add[2][pos]]+zzz)/n);
    	    			vis[i]=0; num[add[y][pos]]=-1;
    	    		}
    	    	}
    		else{  //如果答案代表的数被其它字母占了,那么这组解一定不合法,也没有搜的必要了
    			if((num[add[1][pos]]+num[add[2][pos]]+zzz)%n!=num[add[3][pos]]){
    	    		return ;
    	    	}
    	    	else dfs(pos-1,1,(num[add[1][pos]]+num[add[2][pos]]+zzz)/n); //处理进位
    		}
        }
        else if(num[add[y][pos]]==-1){
        	for(int i=0;i<=n-1;i++){
    	        if(!vis[i]){
    	            vis[i]=1; num[add[y][pos]]=i;
    	            for(int j=0;j<=n-1;j++){  //从整体上扫一遍算式,判断合不合法
                    	if(num[add[1][j]]!=-1&&num[add[2][j]]!=-1&&num[add[3][j]]!=-1){
                    		if((num[add[1][j]]+num[add[2][j]])%n!=num[add[3][j]]&&(num[add[1][j]]+num[add[2][j]]+1)%n!=num[add[3][j]]){  //我懒,不想考虑进位了,直接进不进位都判断一下,应该会跑得慢一些
                    			vis[i]=0; num[add[y][pos]]=-1; flag=1; break;
                    		}
                    	}
                    }
                    if(flag){
                    	flag=0; continue;
                    }
    	            dfs(pos,y+1,zzz);
    	            vis[i]=0; num[add[y][pos]]=-1;
    	        }
    	    }
        }
        else dfs(pos,y+1,zzz);
    
    }
    int main(){
        scanf("%d",&n);
        memset(num,-1,sizeof(num));
        cin>>add[1]>>add[2]>>add[3];
        dfs(n-1,1,0);
        return 0;
    }
    
  • 相关阅读:
    android 多线程
    Uva 10881 Piotr’s Ants 蚂蚁
    LA 3708 Graveyard 墓地雕塑 NEERC 2006
    UVa 11300 Spreading the Wealth 分金币
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    HDU 4162 Shape Number
    HDU 1869 六度分离
    HDU 1041 Computer Transformation
    利用可变参数函数清空多个数组
  • 原文地址:https://www.cnblogs.com/morslin/p/11854810.html
Copyright © 2011-2022 走看看