// Input: CASE_NUM\n CASE{A..L A..L w\n A..L A..L w\n A..L w\n}
// w = up down even
// Output: K is the counterfeit coin and it is light.
// Method: 12 coins, 11 true
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <math.h>
// ENUMS
enum eWeiType
{
wtError = -1, wtEven, wtUp, wtDown,
};
enum eCoinState
{
csUnchecked, csNormal, csBad
};
// STRUCTS
struct SWEIINFO
{
int type;
char lighter[12];
char heavier[12];
};
struct SCOINSTATE
{
int weight;
int state;
int badFlag;
};
// VARS
char lines[3][100];
SCOINSTATE coins[12];
SWEIINFO infos[3];
char buf[3][100];
// FUNCS
// split line to 3 strings
void splitLine(char *&lhs, char *&rhs, char *&type, char *line)
{
// reset buf
memset(buf, 0, sizeof(buf));
// find the second
int len = strlen(line);
int start = 0;
while (start < len && line[start] != ' ')
++ start;
if (start >= len)
return;
lhs = buf[0];
strncpy(buf[0], line, start);
buf[0][start] = 0;
// find the type
int start1 = start + 1;
while (start1 < len && line[start1] != ' ')
++ start1;
if (start1 >= len)
return;
rhs = buf[1];
strncpy(buf[1], line + start + 1, start1 - start - 1);
buf[1][start1 - start] = 0;
type = buf[2];
strncpy(buf[2], line + start1 + 1, len - start1 - 1);
buf[2][len - start1] = 0;
}
// get weight type
int getWeiType(char *type)
{
// cmp its type
if (!strcmp(type, "even"))
return wtEven;
else if (!strcmp(type, "up"))
return wtUp;
else if (!strcmp(type, "down"))
return wtDown;
return wtError;
}
// merge 2 string(not use to clear the repeated)
void mergeString(char *out, char *lhs, char *rhs)
{
strcat(lhs, rhs);
strcpy(out, lhs);
}
// analyze each line
void analyzeLine(int i)
{
// split the line
char *lhs = 0;
char *rhs = 0;
char *type = 0;
splitLine(lhs, rhs, type, lines[i]);
// get weight type
infos[i].type = getWeiType(type);
// copy coins
switch (infos[i].type)
{
case wtEven:
{
mergeString(infos[i].lighter, lhs, rhs);
}
break;
case wtUp:
{
strcpy(infos[i].lighter, rhs);
strcpy(infos[i].heavier, lhs);
}
break;
case wtDown:
{
strcpy(infos[i].lighter, lhs);
strcpy(infos[i].heavier, rhs);
}
break;
}
}
void readCase()
{
for (int i = 0; i < 3; ++i)
{
gets(lines[i]);
analyzeLine(i);
}
}
// check normals
bool checkNormal(char *str)
{
int len = strlen(str);
for (int i = 0; i < len; ++i)
{
if (coins[str[i] - 'A'].state != csNormal)
return false;
}
return true;
}
// has normal coins
int hasNormal(char *str)
{
int count = 0;
int len = strlen(str);
for (int i = 0; i < len; ++i)
{
if (coins[str[i] - 'A'].state == csNormal)
++ count;
}
return count;
}
// set normals
void setNormals(char *str)
{
int i = 0;
while (str[i])
{
coins[str[i] - 'A'].state = csNormal;
++ i;
}
}
// set bad flag
void setBadFlag(char *str)
{
int i = 0;
while (str[i])
{
if (coins[str[i] - 'A'].state != csNormal)
coins[str[i] - 'A'].badFlag = 1;
++ i;
}
}
// calc weights
void calcWeights(char *lighter, char *heavier)
{
int i = 0;
while (lighter[i])
{
-- coins[lighter[i] - 'A'].weight;
++ i;
}
i = 0;
while (heavier[i])
{
++ coins[heavier[i] - 'A'].weight;
++ i;
}
}
// handle infos i
void handleInfos(int i)
{
switch (infos[i].type)
{
case wtEven:
{
setNormals(infos[i].lighter);
}
break;
case wtUp:
case wtDown:
{
setBadFlag(infos[i].lighter);
setBadFlag(infos[i].heavier);
calcWeights(infos[i].lighter, infos[i].heavier);
}
break;
}
}
// count weight values
int countWeightValues(char *str, int &valIndex, int &val, int &cntVal)
{
valIndex = -1;
val = 0;
cntVal = 0;
int values[10] = {0};
int cntValues[10] = {0};
int valIndices[10] = {0};
int count = 0;
// get value counts
int len = strlen(str);
int i;
for (i = 0; i < len; ++i)
{
// find equal
bool found = false;
int w = coins[str[i] - 'A'].weight;
if (coins[str[i] - 'A'].state == csNormal)
w = 0;
for (int j = 0; j < count; ++j)
{
if (values[j] == w)
{
found = true;
++ cntValues[j];
break;
}
}
// not found then add it
if (!found)
{
valIndices[count] = i;
cntValues[count] = 1;
values[count ++] = w;
}
}
// find min
int minCount = 100;
int minIndex = -1;
for (i = 0; i < count; ++i)
{
if (cntValues[i] < minCount)
{
minCount = cntValues[i];
minIndex = i;
}
// if counts equal then take the abs max value
else if (cntValues[i] == minCount && abs(values[i]) > abs(values[minIndex]))
{
minCount = cntValues[i];
minIndex = i;
}
}
if (-1 != minIndex)
{
valIndex = valIndices[minIndex];
val = values[minIndex];
cntVal = cntValues[minIndex];
}
return count;
}
// get first bad flag one and not normal
int getFirstBad(int &lighter)
{
for (int i = 0; i < 12; ++i)
{
if (coins[i].badFlag && coins[i].state != csNormal)
{
if (coins[i].weight > 0)
lighter = 0;
return i;
}
}
return -1;
}
// find different one by take last info as example
int findDiff(int &lighter)
{
lighter = 1;
// get last info
char lastInfo[20] = {0};
strcpy(lastInfo, infos[2].lighter);
strcat(lastInfo, infos[2].heavier);
// count weight values
int minIndex, minVal, minValCount;
int count = countWeightValues(lastInfo, minIndex, minVal, minValCount);
if (count > 1 && minValCount == 1)
{
if (minVal > 0)
lighter = 0;
return (lastInfo[minIndex] - 'A');
}
else if (count > 1)
{
return getFirstBad(lighter);
}
return -1;
}
// print result
void output(char coin, int lighter)
{
printf("%c is the counterfeit coin and it is ", coin);
if (lighter)
printf("light.\n");
else
printf("heavy.\n");
}
void solve()
{
// reset coins state
memset(coins, 0, sizeof(coins));
// sort coin infos by type
int i;
for (i = 0; i < 2; ++i)
{
for (int j = i+1; j < 3; ++j)
{
if (infos[j].type < infos[i].type)
{
SWEIINFO temp = infos[j];
infos[j] = infos[i];
infos[i] = temp;
}
}
}
// handle infos
for (i = 0; i < 3; ++i)
handleInfos(i);
// find different one
int lighter;
int index = findDiff(lighter);
output('A'+index, lighter);
}
#define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif
int caseNum;
scanf("%d\n", &caseNum);
for (int i = 0; i < caseNum; ++i)
{
readCase();
solve();
}
return 0;
}
POJ-1013-Counterfeit Dollar
最新推荐文章于 2019-12-16 22:48:33 发布