P1092 虫食算
Description
所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:
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个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解
Put In
包含四行。第一行有一个正整数N(N<=26),后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。
Put Out
包含一行。在这一行中,应当包含唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。
Sample
5
ABCED
BDACE
EBBAA
1 0 3 4 2
Hints
对于30%的数据,保证有N<=10;
对于50%的数据,保证有N<=15;
对于全部的数据,保证有N<=26。
noip2004提高组第4题
Solution
听说正解是高斯消元呐,但是我不会~(>_<)~
看到大家都写了搜索。
一种实现很简单的方法是枚举1~n的排列,判断是否可行。我算了算时间复杂度(其实我不会算,就大概估计了一下),发现会超时。
由于不会算复杂度,我对于这样的暴搜能过50表示惊讶⊙ o ⊙
如果按照竖式从右至左的顺序搜,就可以边搜边判断是否可行了。
我写得很麻烦,讨论了很多情况,但是很多复制粘贴就可以了。
具体的:
用v[i]记录i所代表的值,use[i]记录是否有字母代表i这个数字。
搜索的时候,传入的参数有:当前到了哪一位,上一位是否进位。
然后搜到某一位的时候,判断哪些数被确定了,我分了0个,1个,2个,3个的情况,分别处理
(如果有多个没有确定,也只能枚举一个,然后进入下一个搜索,因为可能会出现,加数与加数或和的这一位是同一个字母的情况)
有一个剪枝是,搜到第i位的时候,判断一下第i位到第n位,有没有出现冲突的情况(冲突,即三个数都确定了,但是相加什么的并不符合条件)
还有比较神奇的优化,比如枚举的时候倒着枚举。
注意进位什么的。
经过和zcx的讨论后,我终于知道自己代码为什么这么长了。
学习了正常的方法。
搜索的时候,如果当前列有两个数不确定,就跳过这一列(就不用那么多分类讨论了)。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
int n,a[31],b[31],c[31],v[31];
int use[31];
inline int read()
{
register int ans=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {ans=ans*10+ch-'0';ch=getchar();}
return ans*f;
}
int buf[5];
inline void write(int x)
{
if (x<0) putchar('-'),x=-x;
buf[0]=0;
while (x) buf[++buf[0]]=x%10,x/=10;
if (!buf[0]) buf[0]=1,buf[1]=0;
while (buf[0]) putchar('0'+buf[buf[0]--]);
}
bool flag=0;
inline void init()
{
for(register int j=1;j<=n;++j)
{
a[n-j+1]=getchar();
while(a[n-j+1]<'A'||a[n-j+1]>'A'+n-1)
a[n-j+1]=getchar();
a[n-j+1]-='A';
}
for(register int j=1;j<=n;++j)
{
b[n-j+1]=getchar();
while(b[n-j+1]<'A'||b[n-j+1]>'A'+n-1)
b[n-j+1]=getchar();
b[n-j+1]-='A';
}
for(register int j=1;j<=n;++j)
{
c[n-j+1]=getchar();
while(c[n-j+1]<'A'||c[n-j+1]>'A'+n-1)
c[n-j+1]=getchar();
c[n-j+1]-='A';
}
}
void dfs(int now,int in) //当前到哪一位,进位
{
int o;
if(now==n+1)
{
flag=1;
return;
}
for(int i=now;i<=n;i++)
if(v[a[i]]>-1&&v[b[i]]>-1&&v[c[i]]>-1)
{
if((v[a[i]]+v[b[i]])%n==v[c[i]]||(v[a[i]]+v[b[i]]+1)%n==v[c[i]])
continue;
else
return;
}
if(v[a[now]]>-1&&v[b[now]]>-1&&v[c[now]]>-1)
{
if(v[a[now]]+v[b[now]]+in==v[c[now]]||(now!=n&&(v[a[now]]+v[b[now]]+in)%n==v[c[now]]))
{
dfs(now+1,(v[a[now]]+v[b[now]]+in)/n);
if(flag)
return;
}
else
return;
}
if(v[a[now]]>-1&&v[b[now]]>-1&&v[c[now]]==-1)
{
if((v[a[now]]+v[b[now]]+in<n||now!=n)&&!use[(v[a[now]]+v[b[now]]+in)%n])
{
v[c[now]]=(v[a[now]]+v[b[now]]+in)%n;
use[v[c[now]]]=1;
dfs(now+1,(v[a[now]]+v[b[now]]+in)/n);
if(flag)
return;
use[v[c[now]]]=0;
v[c[now]]=-1;
}
else
return;
}
if(v[a[now]]>-1&&v[b[now]]==-1&&v[c[now]]>-1)
{
if((v[c[now]]>v[a[now]]+in||now!=n)&&!use[(v[c[now]]-v[a[now]]-in+n)%n])
{
v[b[now]]=(v[c[now]]-v[a[now]]-in+n)%n;
use[v[b[now]]]=1;
dfs(now+1,(v[a[now]]+v[b[now]]+in)/n);
if(flag)
return;
use[v[b[now]]]=0;
v[b[now]]=-1;
}
else
return;
}
if(v[b[now]]>-1&&v[a[now]]==-1&&v[c[now]]>-1)
{
if(v[c[now]]>v[b[now]]+in||now!=n)
{
v[a[now]]=(v[c[now]]-v[b[now]]-in+n)%n;
use[v[a[now]]]=1;
dfs(now+1,(v[b[now]]+v[a[now]]+in)/n);
if(flag) return;
use[v[a[now]]]=0;
v[a[now]]=-1;
}
else
return;
}
if(v[a[now]]>-1&&v[b[now]]==-1&&v[c[now]]==-1)
{
o=n==now? n-v[a[now]]-in:n-in;
for(register int i=o-1;i>=0;--i)
if(!use[i])
{
v[b[now]]=i;use[i]=1;
dfs(now,in);
if(flag)
return;
use[i]=0;v[b[now]]=-1;
}
}
if(v[a[now]]==-1&&v[b[now]]>-1&&v[c[now]]==-1)
{
o=n==now? n-v[b[now]]-in:n-in;
for(register int i=o-1;i>=0;--i)
if(!use[i])
{
v[a[now]]=i;use[i]=1;
dfs(now,in);
if(flag)
return;
use[i]=0;v[a[now]]=-1;
}
}
if(v[a[now]]==-1&&v[b[now]]==-1&&v[c[now]]>-1)
{
o=n==now? v[c[now]]-in:n-1-in;
for(register int i=o;i>=0;--i)
if(!use[i])
{
v[a[now]]=i;use[i]=1;
dfs(now,in);
if(flag) return;
v[a[now]]=-1;use[i]=0;
}
}
if(v[a[now]]==-1&&v[b[now]]==-1&&v[c[now]]==-1)
{
o=n==now? n-in:n;
for(register int i=o-1;i>=0;--i)
if(!use[i])
{
v[a[now]]=i;use[i]=1;
dfs(now,in);
if(flag) return;
v[a[now]]=-1;use[i]=0;
}
}
}
int main()
{
n=read();
init();
for(register int i=0;i<n;++i)
{
use[i]=0;
v[i]=-1;
}
dfs(1,0);
for(register int i=0;i<n;++i)
{
write(v[i]);
putchar(' ');
}
return 0;
}