洛谷P1092虫食算

题意:

略略略

ABCED
BDACE
EBBAA

上面式子的意思是:

第一行和第二行是加数,第三行是结果。

并且这是n进制加法,每个字母代表0--n-1中一个。

字母和数字一一对应。

这个的结果是1 0 3 4 2

10324

04132

20011

(允许有前导0)

10进制加法是满十进一,N进制加法是满n进1.

(4+2)%5=1;(2+3+1)%5=1;......

题解:

一、数组:

ans[]记录答案,ans[0]代表A对应的数字,开始赋值为-1.

不能赋值为0,因为0可以为对应的数字。

use[]标记数字是否被占用。use[0]=true,表示数字0已经赋值给别的字母了。

二、剪枝:

先来几个普通的剪枝,(如果想看更多剪枝就看其他题解吧...)

1)首先是n位,所以最高位不能进1,否则结果是n+1位。

2)知二推一。

情况一:知道两个加数和结果(假设为a,b,c),我们可以算出结果为(a+b)%n。

但我们不知道之前是否有进位。那么如果c既不等于(a+b)%n,也不等于(a+b+1)%n,

那么c一定是不对的了。

情况二:知道c和a,b中的一个,假设知道b,那么a=c-b。若a<0,a+=n;

如果现在推出的a这个数已经被其他字母占用了,并且a-1(有进位)不存在,即<0,

或者存在但也被其他字母占用了,那么就没有数字对应这个字母,需要return。

三、搜索顺序(各个顺序的代码和所用时间后面会给出)

1)按顺序,从A开始搜每个字母代表的数字。

2)按照我们手推的顺序,从左到右,从上到下,以列一列的搜。

3)跟第二种差不多..或者一楼的next数组就是这个意思?【笑

在做靶形数独这个题时,有一种搜的方法是把没填的格子位置记录下来,

在搜时从当前没填的格子直接跳到下一个没填的格子,不用遍历整张图。

我们按手推的顺序(上到下,左到右)把遇到的一个个字母装入一个数组中。

不是从A、B、C....搜,而是从我们手推遇到字母的顺序搜。

如样例:搜索顺序就是DEACB...

时间和第二种顺序差不多

4)倒着搜...玄学

四、代码

【代码一】70  3740ms  从A搜

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;

char s1[30],s2[30],s3[30];

int A[30],B[30],C[30];

bool use[30];

int ans[30];

void print()
{
    for(int i=0;i<n;i++) printf("%d ",ans[i]);
    exit(0);
}

bool ok()
{
    int x=0;
    for(int i=n;i>=1;i--)
    {
        int a=ans[A[i]],b=ans[B[i]],c=ans[C[i]];
        if((a+b+x)%n!=c)return false;
        x=(a+b+x)/n;
    }
    return true;
}

bool check()
{
    for(int i=n;i>=1;i--)
    {
        int a=ans[A[i]],b=ans[B[i]],c=ans[C[i]];
        if(i==1&&a+b>n)return false;
        if(a!=-1&&b!=-1&&c!=-1)
        {
            if((a+b)%n!=c&&(a+b+1)%n!=c) return false;
        }
        if(a==-1&&b!=-1&&c!=-1)
        {
            int d=c-b;
            if(d<0)d+=n;
            if(use[d]&&use[d-1])return false;
        }
        if(a!=-1&&b==-1&&c!=-1)
        {
            int d=c-a;
            if(d<0)d+=n;
            if(use[d]&&use[d-1])return false;
        }
    }
    return true;
}

void dfs(int now)
{
    if(now==n)
    {
        if(ok())print();
        return;
    }
    if(check()==false)return;
    for(int i=0;i<n;i++)
    {
        if(!use[i])
        {
            use[i]=true;
            ans[now]=i;
            dfs(now+1);
            use[i]=false;
            ans[now]=-1;
        }
    }
}

int main()
{
    scanf("%d",&n);
    scanf("%s%s%s",s1+1,s2+1,s3+1);
    for(int i=1;i<=n;i++)
    {
        A[i]=s1[i]-'A';
        B[i]=s2[i]-'A';
        C[i]=s3[i]-'A';
    }    
    for(int i=0;i<n;i++)ans[i]=-1;
    dfs(0);
    return 0;
}

 

【代码二】按手推顺序搜  94ms

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;

int pos[4][40];

int ans[30];

char s1[30],s2[30],s3[30];

bool use[30];

void print()
{
    for(int i=0;i<n;i++) printf("%d ",ans[i]);
    exit(0);
}

bool ok()
{
    int x=0;
    for(int i=n;i>=1;i--)
    {
        int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
        int xx=a+b+x;
        if(xx%n!=c) return false;
        x=xx/n;
    }
    return true;
}

bool check()
{
    if(ans[pos[1][1]]+ans[pos[2][1]]>=n) return false;
    for(int i=1;i<=n;i++)
    {
        int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
        if(a!=-1&&b!=-1&&c!=-1)
        {
            if((a+b)%n!=c&&(a+b+1)%n!=c) return false;
        }
        if(a!=-1&&b==-1&&c!=-1)
        {
            int d=c-a;
            if(d<0) d+=n;
            if(use[d]&&(d-1<0||use[d-1])) return false; 
        }
        if(a==-1&&b!=-1&&c!=-1)
        {
            int d=c-b;
            if(d<0)d+=n;
            if(use[d]&&(d-1<0||use[d-1])) return false;
        }
    }
    return true;
}

void dfs(int x,int y,int has)
{
    if(has==n)
    {
        if(ok()) print();
        return;
    }
    if(check()==false) return;
    if(y==0) return ;
    if(ans[pos[x][y]]!=-1)
    {
        if(x==3) dfs(1,y-1,has);
        else dfs(x+1,y,has);
    }else
    {
        for(int i=n-1;i>=0;i--)
        {
            if(!use[i])
            {
                use[i]=true;
                ans[pos[x][y]]=i;
                if(x==3)dfs(1,y-1,has+1);
                else dfs(x+1,y,has+1);
                use[i]=false;
                ans[pos[x][y]]=-1;
            }
        }
    }
}

int main()
{
    scanf("%d",&n);
    scanf("%s%s%s",s1+1,s2+1,s3+1);
    for(int i=1;i<=n;i++)
    {
        pos[1][i]=s1[i]-'A';
        pos[2][i]=s2[i]-'A';
        pos[3][i]=s3[i]-'A';
    }
    for(int i=0;i<n;i++)ans[i]=-1;
    dfs(1,n,0);
    return 0;
}

 

代码三】 91ms 这样搜仿佛没什么卵用 :-)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,cnt;

int pos[4][30],k[30],ans[30];

char s1[30],s2[30],s3[30];

bool use[30];

void print()
{
    for(int i=0;i<n;i++) printf("%d ",ans[i]);
    exit(0);
}

bool ok()
{
    int x=0;
    for(int i=n;i>=1;i--)
    {
        int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
        int xx=a+b+x;
        if(xx%n!=c) return false;
        x=xx/n;
    }
    return true;
}

bool check()
{
    if(ans[pos[1][1]]+ans[pos[2][1]]>=n) return false;
    for(int i=1;i<=n;i++)
    {
        int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]];
        if(a!=-1&&b!=-1&&c!=-1)
        {
            if((a+b)%n!=c&&(a+b+1)%n!=c) return false;
        }
        if(a!=-1&&b==-1&&c!=-1)
        {
            int d=c-a;
            if(d<0) d+=n;
            if(use[d]&&(d-1<0||use[d-1])) return false; 
        }
        if(a==-1&&b!=-1&&c!=-1)
        {
            int d=c-b;
            if(d<0)d+=n;
            if(use[d]&&(d-1<0||use[d-1])) return false;
        }
    }
    return true;
}

void dfs(int now)
{
    if(now==n+1)
    {
        if(ok()) print();
        return ;
    }
    if(check()==false) return;
    for(int i=n-1;i>=0;i--)
    {
        if(use[i]) continue;
        int anow=k[now];
        use[i]=true;
        ans[anow]=i;
        dfs(now+1);
        use[i]=false;
        ans[anow]=-1;
    }
}

int main()
{
    scanf("%d",&n);
    scanf("%s%s%s",s1+1,s2+1,s3+1);
    for(int i=n;i>=1;i--)
    {
        pos[1][i]=s1[i]-'A'; if(!use[pos[1][i]])k[++cnt]=pos[1][i],use[pos[1][i]]=true;
        pos[2][i]=s2[i]-'A'; if(!use[pos[2][i]])k[++cnt]=pos[2][i],use[pos[2][i]]=true;
        pos[3][i]=s3[i]-'A'; if(!use[pos[3][i]])k[++cnt]=pos[3][i],use[pos[3][i]]=true;
    }
    memset(use,0,sizeof(use));
    memset(ans,-1,sizeof(ans));
    dfs(1);
    return 0;
} 

 

posted @ 2020-06-24 20:11  ANhour  阅读(177)  评论(0编辑  收藏  举报