#define MAX_LENGTH 3
enum DigitUnit
{
OneDigit = 1,
TenDigit = 10,
HundredDigit = 100,
ThousandDigit = 1000,
MaxDigit = 100000,
};
struct RomeTrieNode
{
char Latin;
int Value;
int NoOfChild;
struct RomeTrieNode* Next[MAX_LENGTH];
};
struct RomeTrieNode Ones[9] =
{
{'I', 1, 3, {Ones+2,Ones+3,Ones+4}},
{'V', 5, 1, {Ones+6, 0, 0}},
{'I', 2, 1, {Ones+5, 0, 0}},
{'V', 4, 0, {0, 0, 0}},
{'X', 9, 0, {0, 0, 0}},
{'I', 3, 0, {0, 0, 0}},
{'I', 6, 1, {Ones+7, 0, 0}},
{'I', 7, 1, {Ones+8, 0, 0}},
{'I', 8, 0, {0, 0, 0}},
};
struct RomeTrieNode Tens[9] =
{
{'X', 10, 3, {Tens+2,Tens+3,Tens+4}},
{'L', 50, 1, {Tens+6, 0, 0}},
{'X', 20, 1, {Tens+5, 0, 0}},
{'L', 40, 0, {0, 0, 0}},
{'C', 90, 0, {0, 0, 0}},
{'X', 30, 0, {0, 0, 0}},
{'X', 60, 1, {Tens+7, 0, 0}},
{'X', 70, 1, {Tens+8, 0, 0}},
{'X', 80, 0, {0, 0, 0}},
};struct RomeTrieNode Hundreds[9] =
{
{'C', 100, 3, {Hundreds+2,Hundreds+3,Hundreds+4}},
{'D', 500, 1, {Hundreds+6, 0, 0}},
{'C', 200, 1, {Hundreds+5, 0, 0}},
{'D', 400, 0, {0, 0, 0}},
{'M', 900, 0, {0, 0, 0}},
{'C', 300, 0, {0, 0, 0}},
{'C', 600, 1, {Hundreds+7, 0, 0}},
{'C', 700, 1, {Hundreds+8, 0, 0}},
{'C', 800, 0, {0, 0, 0}},
};
struct RomeTrieNode Thousands[9] =
{
{'M', 1000, 1, {Thousands+1,0, 0}},
{'M', 2000, 1, {Thousands+2, 0, 0}},
{'M', 3000, 0, {0, 0, 0}},
};
struct RomeTrieNode* FindBegin(char latin, DigitUnit* curDigit)
{
DigitUnit nextDigit = MaxDigit;
struct RomeTrieNode* head = 0;
switch(latin)
{
case 'I':
nextDigit = OneDigit;
head = Ones;
break;
case 'V':
nextDigit = OneDigit;
head = Ones+1;
break;
case 'X':
nextDigit = TenDigit;
head = Tens;
break;
case 'L':
nextDigit = TenDigit;
head = Tens+1;
break;
case 'C':
nextDigit = HundredDigit;
head = Hundreds;
break;
case 'D':
nextDigit = HundredDigit;
head = Hundreds+1;
break;
case 'M':
nextDigit = ThousandDigit;
head = Thousands;
break;
default: return 0;
}
if (nextDigit < *curDigit)
{
*curDigit = nextDigit;
return head;
}
return 0;
}
int RomeToInteger(char* roman)
{
if (*roman == '\0') return 0;
int value = 0;
struct RomeTrieNode* curNode = 0;
struct RomeTrieNode* nextNode = 0;
DigitUnit curDigit = MaxDigit;
curNode = FindBegin(*roman,&curDigit);
if (!curNode) return 0;
for(char* r = roman+1; *r; ++r)
{
nextNode = 0;
for (int i = 0; i < curNode->NoOfChild ; ++i)
if (curNode->Next[i]->Latin == *r)
{
nextNode = curNode->Next[i];
break;
}
if (!nextNode)
{
value += curNode->Value;
curNode = FindBegin(*r, &curDigit);
if (!curNode) return 0;
}
else
{
curNode = nextNode;
}
}
value += curNode->Value;
return value;
}
int main(int argc, char** argv)
{
char roman[10] ="MMXII";
printf("%s: %d",roman, RomeToInteger(roman));
return 0;
}