1. 程式人生 > >洛谷 P1092 蟲食算

洛谷 P1092 蟲食算

輸入輸出 正整數 abcd .com pos nbsp 給定 輸入數據 targe

P1092 蟲食算

題目描述

所謂蟲食算,就是原先的算式中有一部分被蟲子啃掉了,需要我們根據剩下的數字來判定被啃掉的字母。來看一個簡單的例子:

http://paste.ubuntu.com/25448822/

其中#號代表被蟲子啃掉的數字。根據算式,我們很容易判斷:第一行的兩個數字分別是5和3,第二行的數字是5。

現在,我們對問題做兩個限制:

首先,我們只考慮加法的蟲食算。這裏的加法是N進制加法,算式中三個數都有N位,允許有前導的0。

其次,蟲子把所有的數都啃光了,我們只知道哪些數字是相同的,我們將相同的數字用相同的字母表示,不同的數字用不同的字母表示。如果這個算式是N進制的,我們就取英文字母表午的前N個大寫字母來表示這個算式中的0到N-1這N個不同的數字:但是這N個字母並不一定順序地代表0到N-1)。輸入數據保證N個字母分別至少出現一次。

http://paste.ubuntu.com/25448824/

上面的算式是一個4進制的算式。很顯然,我們只要讓ABCD分別代表0123,便可以讓這個式子成立了。你的任務是,對於給定的N進制加法算式,求出N個不同的字母分別代表的數字,使得該加法算式成立。輸入數據保證有且僅有一組解

輸入輸出格式

輸入格式:

包含四行。第一行有一個正整數N(N<=26),後面的3行每行有一個由大寫字母組成的字符串,分別代表兩個加數以及和。這3個字符串左右兩端都沒有空格,從高位到低位,並且恰好有N位。

輸出格式:

包含一行。在這一行中,應當包含唯一的那組解。解是這樣表示的:輸出N個數字,分別表示A,B,C……所代表的數字,相鄰的兩個數字用一個空格隔開,不能有多余的空格。

輸入輸出樣例

輸入樣例#1: 復制
5
ABCED
BDACE
EBBAA
輸出樣例#1: 復制
1 0 3 4 2

說明

對於30%的數據,保證有N<=10;

對於50%的數據,保證有N<=15;

對於全部的數據,保證有N<=26。

noip2004提高組第4題

思路:簡直太他媽的玄學了!!

兩個剪枝,倒著搜 50

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using
namespace std; int n,cnt; char a[27],b[27],c[27]; int s1[27],s2[27],s3[27]; int num[27],vis[27],net[27]; int jz(){ if(num[s1[0]]+num[s2[0]]>=n) return true; for(int i=n-1;i>=0;i--){ int A=num[s1[i]],B=num[s2[i]],C=num[s3[i]]; if(A==-1||B==-1||C==-1) continue; if((A+B)%n!=C&&(A+B+1)%n!=C) return true; } return false; } int judge(){ int last=0; for(int i=n-1;i>=0;i--){ int A=num[s1[i]],B=num[s2[i]],C=num[s3[i]]; if((A+B+last)%n!=C) return false; last=(A+B+last)/n; } if(last!=0) return false; return true; } void dfs(int now){ if(jz()==true) return ; if(now==n) if(judge()==true){ for(int i=0;i<n;i++) cout<<num[i]<<" "; exit(0); } for(int i=n-1;i>=0;i--) if(!vis[i]){ num[now]=i; vis[i]=1; dfs(now+1); num[now]=-1; vis[i]=0; } } int main(){ scanf("%d",&n); cin>>a>>b>>c; for(int i=0;i<n;i++){ s1[i]=a[i]-A; s2[i]=b[i]-A; s3[i]=c[i]-A; } memset(vis,0,sizeof(vis)); memset(num,-1,sizeof(num)); dfs(0); return 0; }

兩個剪枝,正著搜:70

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,cnt;
char a[27],b[27],c[27];
int s1[27],s2[27],s3[27];
int num[27],vis[27],net[27];
int jz(){
    if(num[s1[0]]+num[s2[0]]>=n)    return true;    
    for(int i=n-1;i>=0;i--){
        int A=num[s1[i]],B=num[s2[i]],C=num[s3[i]];
        if(A==-1||B==-1||C==-1)    continue;
        if((A+B)%n!=C&&(A+B+1)%n!=C)    return true;
    }
    return false;
}
int judge(){
    int last=0;
    for(int i=n-1;i>=0;i--){
        int A=num[s1[i]],B=num[s2[i]],C=num[s3[i]];
        if((A+B+last)%n!=C)    return false;
        last=(A+B+last)/n;
    }
    if(last!=0)    return false;
    return true;
}
void dfs(int now){
     if(jz()==true)    return ;
    if(now==n)
        if(judge()==true){
            for(int i=0;i<n;i++)
                cout<<num[i]<<" ";
            exit(0);
        }
    for(int i=0;i<n;i++)
        if(!vis[i]){
            num[now]=i;
            vis[i]=1;
            dfs(now+1);
            num[now]=-1;
            vis[i]=0;
        }
}
int main(){
    scanf("%d",&n);
    cin>>a>>b>>c;
    for(int i=0;i<n;i++){
        s1[i]=a[i]-A;
        s2[i]=b[i]-A;
        s3[i]=c[i]-A;
    }
    memset(vis,0,sizeof(vis));
    memset(num,-1,sizeof(num));
    dfs(0);
    return 0;
}

倒著搜+兩個剪枝+玄學剪枝

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,cnt;
char a[27],b[27],c[27];
int s1[27],s2[27],s3[27];
int num[27],vis[27],net[27];
int jz(){
    if(num[s1[0]]+num[s2[0]]>=n)    return true;    
    for(int i=n-1;i>=0;i--){
        int A=num[s1[i]],B=num[s2[i]],C=num[s3[i]];
        if(A==-1||B==-1||C==-1)    continue;
        if((A+B)%n!=C&&(A+B+1)%n!=C)    return true;
    }
    return false;
}
int judge(){
    int last=0;
    for(int i=n-1;i>=0;i--){
        int A=num[s1[i]],B=num[s2[i]],C=num[s3[i]];
        if((A+B+last)%n!=C)    return false;
        last=(A+B+last)/n;
    }
    if(last!=0)    return false;
    return true;
}
void dfs(int now){
     if(jz()==true)    return ;
    if(now==n)
        if(judge()==true){
            for(int i=0;i<n;i++)
                cout<<num[i]<<" ";
            exit(0);
        }
    for(int i=n-1;i>=0;i--)
        if(!vis[i]){
            num[net[now]]=i;
            vis[i]=1;
            dfs(now+1);
            num[net[now]]=-1;
            vis[i]=0;
        }
}
void getnet(int x){
    if(vis[x]==0){
        net[cnt++]=x;
        vis[x]=1;
    }
    return ;
}
int main(){
    scanf("%d",&n);
    cin>>a>>b>>c;
    for(int i=0;i<n;i++){
        s1[i]=a[i]-A;
        s2[i]=b[i]-A;
        s3[i]=c[i]-A;
    }
    for(int i=n-1;i>=0;i--){
        getnet(s1[i]);
        getnet(s2[i]);
        getnet(s3[i]);
    }
    memset(vis,0,sizeof(vis));
    memset(num,-1,sizeof(num));
    dfs(0);
    return 0;
}

洛谷 P1092 蟲食算