/*1.转换数字 2.判断罗马等式 3.回溯穷举阿拉伯等式,统计、输出
耗时一天,自己做出来了,很爽。
WA了两次,原因:一开始理解错题意,还以为不考虑0
Assume that zero will never appear on its own or as a leading digit,
and that no two Roman numerals map onto the same Arabic digit.
WA了两次才搞明白这句话的意思是0不能单独出现,而且不能作为前导。例如XL你不能写成01.
*/
#include<stdio.h>
#include<string.h>
char Roman[50];//记录等式
int Rleft,Rright,Rsum,Correct;//用于计算罗马等式
int Aleft,Aright,Asum,Once;//用于计算阿拉伯等式
int value[8]={0,1,5,10,50,100,500,1000};//与下个数组形成映射好把罗马数转换成数值
char word[8]={' ','I','V','X','L','C','D','M'};
int state[3],tag[50];//state用于记录impossible、ambiguous和valid,tag用于标记罗马字母,便于计算出数值
int vis[10],hash[8],unzero[8];//vis用于DFS时穷举全排列,hash用于存出现过的字母下标,unzero作为hash的映射,存有几个字母出现过
int All;//存共出现过的字母
int TransfertoRNum()//将罗马字母转换成数值
{
int i,j,k;
for(i=0;i<strlen(Roman)-1;i++)
{
if(tag[i])
{
if(tag[i]>=tag[i+1])
{
Rleft+=value[tag[i]];//直接将字母映射成数值计算
}
else
{
Rleft-=value[tag[i]];
}
}
else break;
}
for(j=i+1;j<strlen(Roman)-1;j++)
{
if(tag[j])
{
if(tag[j]>=tag[j+1])
{
Rright+=value[tag[j]];
}
else
{
Rright-=value[tag[j]];
}
}
else break;
}
for(i=j+1;i<strlen(Roman);i++)
{
if(tag[i])
{
if(tag[i]>=tag[i+1])
{
Rsum+=value[tag[i]];
}
else
{
Rsum-=value[tag[i]];
}
}
}
}
int AcquireUnzero()//获取unzero数组
{
int i,j=0;
for(i=1;i<=7;i++)
{
if(hash[i])unzero[j++]=i;
}
All=j;
return 0;
}
int TransfertoAnum()//将罗马等式转换成阿拉伯等式
{
int i,j,k;
for(i=0;i<strlen(Roman)-1;i++)
{
if(tag[i])
{
Aleft=Aleft*10+hash[tag[i]];
if(!Aleft)return 0;//出现前导0或者自身是0,返回
}
else break;
}
for(j=i+1;j<strlen(Roman)-1;j++)
{
if(tag[j])
{
Aright=Aright*10+hash[tag[j]];
if(!Aright)return 0;
}
else break;
}
for(i=j+1;i<strlen(Roman);i++)
{
if(tag[i])
{
Asum=Asum*10+hash[tag[i]];
if(!Asum)return 0;
}
else break;
}
return 1;
}
int DFS(int cur)//回溯穷举所有情况
{
int i,j,k;
if(cur>=All)
{
if(TransfertoAnum()&&Aleft+Aright==Asum)
{
Once++;
/* printf("%d + %d = %d\n",Aleft,Aright,Asum);*/
if(Once>1)return 1;//一旦满足两次,肯定是ambiguous,直接返回
}
Aleft=Aright=Asum=0;
return 0;
}
for(i=0;i<10;i++)
{
if(!vis[i])
{
hash[unzero[cur]]=i;
vis[i]=1;
if(DFS(cur+1))return 1;
vis[i]=0;
}
}
return 0;
}
int main()
{
int i,j,k;
while(gets(Roman)&&Roman[0]!='#')
{
All=Correct=0;
Rleft=Rright=Rsum=0;
Aleft=Aright=Asum=Once=0;
memset(state,0,sizeof(state));
memset(tag,0,sizeof(tag));
memset(vis,0,sizeof(vis));
memset(hash,0,sizeof(hash));
memset(unzero,0,sizeof(unzero));
for(i=0;i<strlen(Roman);i++)
{
for(j=1;j<=7;j++)
{
if(Roman[i]==word[j])
{
tag[i]=j;
hash[j]++;
break;
}
}
}
AcquireUnzero();
TransfertoRNum();
/*printf("%d + %d =%d\n",Rleft,Rright,Rsum);*/
if(Rleft+Rright==Rsum)Correct=1;
DFS(0);
switch(Once)
{
case 0:state[0]=1;break;
case 2:state[1]=1;break;
case 1:state[2]=1;break;
default:
state[1]=1;
}
if(Correct)
{
if(state[0])
printf("Correct impossible\n");
else if(state[1])
printf("Correct ambiguous\n");
else if(state[2])
printf("Correct valid\n");
}
else
{
if(state[0])
printf("Incorrect impossible\n");
else if(state[1])
printf("Incorrect ambiguous\n");
else if(state[2])
printf("Incorrect valid\n");
}
}
return 0;
}
UVA - 185 - Roman Numerals
最新推荐文章于 2022-02-25 19:38:17 发布