## CSDN博客

### ACM Asia Regional (Kanpur Site) Programming Contest 2001 Problem H

Problem H

The Most Wanted Man in the History of Mankind

Input : spot.in

Output : standard output

There is a search around the world for the most wanted man (MWM) in the history of mankind. He is believed to have an extraordinary quality, either superior or inferior, compared to a normal person. He is likely to be present any where in the world. If he is spotted precisely then he may be captured without much difficulty. However the problem is in spotting him because a number of look-alikes are known to exist at different parts of the world.

Apart from conventional resources, modern satellite communication and surveillance systems that can precisely identify, measure, record and monitor the physical, social, cultural and behavioral characteristics of a person, are available for collecting data on the MWM. In addition, the services of competent professionals in different disciplines are available to analyze and interpret data collected from all sources.

Professional Psychologists and Statisticians admit that it is difficult for them to distinguish precisely between two persons using physical and behavioral data. However, by analyzing and interpreting group data, they claim that they can differentiate precisely between a group of normal persons and a similar group of same size that includes a person of extraordinary quality even if it is not known in advance whether the extraordinary quality is superior or inferior to that of a normal person. In such a case for a reliable comparison it is necessary that the number of persons in each group is 3 or more.

In other words, let A, B be two groups of equal number of persons, the number being 3 or more. An unidentified person x having an extraordinary quality classified either superior or inferior, may or may not be present in any of the groups. It is possible to perform a special compare operation on A, B and state precisely by data analysis and interpretation, one of the following:

(a) A=B indicating x is neither in A nor in B,

(b) A>B indicating either x is in A and he is superior or x is in B and he is inferior,

(c) A<B indicating either x is in A and he is inferior or x is in B and he is superior.

The outcome of the special compare operation may be denoted by E, H and L representing the cases (a), (b) and (c) respectively.

Since collection, analysis and interpretation of data are considered costly and the total number n of look-alikes including the MWM is small, 8 £ n £ 12, it is decided that only three special compare operations on selected groups could be performed successively to spot the MWM and determine his qualitative characteristic. However it is required to select groups Ai, Bi, i= 1,2,3, before each special compare operation. The groups may depend on the outcome of the previous special compare operations.

Write a program that selects the groups to be compared by the professionals in three stages. For each stage, you may assume that the outcomes of special compare operations are known for all previous stages. After selection of groups the program should spot the MWM when successive outcomes of special compare operations are known.

Input

The input may contain multiple test cases.

The data for a test case are given in a single line. The line contains two integers, the case number c and the total number n of look-alikes, 8 £ n £ 12. It also contains a string S of three letters s1, s2, s3 representing the successive outcomes of three special compare operations to be used by your program to form the groups for comparison and to spot the MWM.

The look-alikes, including the MWM w, are identified by integers 1, 2, …n and each of the outcomes s1, s2, s3 of the special compare operations is represented by the letters E, H or L. The ith letter si in the string S represents the outcome of the ith special compare operation, i=1,2,3.

The entire input set terminates with an input 0 for c.

Output

For each test case in the input, print four lines.

The first line contains the input data, viz., c, n, S, together with an integer w that spots the MWM and a letter q that identifies his quality. If MWM is spotted then 1 £ w £ n and the letter q is either s or i depending on whether the quality of MWM is identified as superior or inferior. If MWM is not among the look-alikes then w is equal to zero and the letter q is equal to m, representing ’MWM missing’. In case the comparisons reveal that the claims of the professionals are faulty, then w is equal to -1 and q is equal to f representing ’faulty comparisons and claims are not tenable’.

The next three lines contain Ai, si, Bi, i =1, 2, 3 where Ai, Bi are the groups for comparison at the ith stage and si is the given outcome of the special compare operation.

Print a blank line between outputs of two test cases.

Sample Input

1 8 HHH

2 8 HHE

3 8 HHL

4 8 HEH

5 8 HEE

6 8 HEL

7 8 HLH

8 8 EEE

0

Sample Output

1 8 HHH 1 s

1 2 3 H 4 5 6

1 4 7 H 2 5 8

1 5 6 H 2 7 8

2 8 HHE -1 f

1 2 3 H 4 5 6

1 4 7 H 2 5 8

1 5 6 E 2 7 8

3 8 HHL 5 i

1 2 3 H 4 5 6

1 4 7 H 2 5 8

1 5 6 L 2 7 8

4 8 HEH -1 f

1 2 3 H 4 5 6

1 4 7 E 2 5 8

1 5 6 H 2 7 8

5 8 HEE 3 s

1 2 3 H 4 5 6

1 4 7 E 2 5 8

1 5 6 E 2 7 8

6 8 HEL 6 i

1 2 3 H 4 5 6

1 4 7 E 2 5 8

1 5 6 L 2 7 8

7 8 HLH -1 f

1 2 3 H 4 5 6

1 4 7 L 2 5 8

1 5 6 H 2 7 8

8 8 EEE 0 m

1 2 3 E 4 5 6

1 4 7 E 2 5 8

1 5 6 E 2 7 8

//Author IPLinger
//IDE VC++
//Data 2004.10.11
//Note 本题类似于经典的称球问题。本题的关键在于构建分组，如何的分组才能在三次中分别称出8，9，10，11，12个球中不同的那
//     个，并说明其轻重。我们可以这样分组 对于8 的分组情况题目已经给出。那么9的分组情况为 1,2,3-4,5,6  1,4,7-2,5,8  1,5,6-2,7,9
//     10的分组情况为 1,2,3,4-5,6,7,8  1,6,7,9-2,5,8,10   1,3,5,7-2,4,6,9
//     11的分组情况为 1,2,3,4-5,6,7,8  1,6,7,9-2,5,10,11  1,5,9,10-2,6,3,8
//     12的分组情况为 1,2,3,4-5,6,7,8  1,6,7,9-2,5,10,11  3,8,9,10-2,5,6,12
//     另一个难点在于如何使用程序找出MWM，也就是坏球。我的做法是这样的：先分别设置3个数组，super，infer，except
//     每次比较如果是'E'则把比较的两组都放入except；
//     如果是'H'分两种情况，如果先前有过'H'或'L'比较则把比较两组的前一组与super取交集放入super，没有则直接把前一组的所有值
//     放入super。如果是'L'分两种情况，如果先前有过'H'或'L'比较则把比较两组的前一组与super取交集放入infer，没有则直接把前一组
//     的所有值放入infer 。最后让super 和 infer两个数组都剪去except中的值。
//    结果：如果从来没有出现'H'或'L'则没有MWM；//如果出现过'H'或'L'，并且最终superM和inferM都被消空了。则说明出现矛盾；
//    如果没有矛盾则根据我们分的组肯定能找出MWM，而且唯一。

#pragma hdrstop
# include <fstream>
# include <string>
# include <iostream>
using namespace std;

int caseNum;
//当前第几个案例
int totalNum;
//total number n of look-alikes
const int operationNum=3;
char operation[operationNum];
//当前操作码
const int maxLengthOfGroup=4;
//每一组最大容量
int superM[maxLengthOfGroup];
int inferM[maxLengthOfGroup];
//计算中存放 有可能取super值得数，和可能取infer值得数
const int exceptLength=12;
int except[exceptLength];
////计算中存放既不去super,又不取infer值得数
bool hOrL=false;
//记录是否进行过'H'或'L'操作，进行过其值为true

class Group
//类Group存储个个比较组
{
public:
Group(int tNum,int numOfOneGroup,int initValue[24])
{
totalNum=tNum;
numOfOG=numOfOneGroup;
for(int i=0;i<6;i++)
for(int j=0;j<numOfOneGroup;j++)
group[i][j]=initValue[i*numOfOG+j];
}
void print()
//为调试用
{
cout << "totalNum=" << totalNum << endl;
cout << "numOfOG=" << numOfOG << endl;
for(int i=0;i<6;i++)
{
cout << "group[" << i << "]: ";
for(int j=0;j<numOfOG;j++)
cout << " " << group[i][j];
cout << endl;
}
}
public:
int totalNum;
//total number n of look-alikes
int numOfOG;
//每一组的数量
int group[6][4];
//一共六个组两两一对，每组最多4个
};

//initialize
int groupValue8[24]={1,2,3,4,5,6,1,4,7,2,5,8,1,5,6,2,7,8};
int groupValue9[24]={1,2,3,4,5,6,1,4,7,2,5,8,1,5,6,2,7,9};
int groupValue10[24]={1,2,3,4,5,6,7,8,1,6,7,9,2,5,8,10,1,3,5,7,2,4,6,9};
int groupValue11[24]={1,2,3,4,5,6,7,8,1,6,7,9,2,5,10,11,1,5,9,10,2,3,6,8};
int groupValue12[24]={1,2,3,4,5,6,7,8,1,6,7,9,2,5,10,11,3,8,9,10,2,5,6,12};
static Group group8(8,3,groupValue8);
static Group group9(9,3,groupValue9);
static Group group10(10,4,groupValue10);
static Group group11(11,4,groupValue11);
static Group group12(12,4,groupValue12);

//////////////////////////////////////////////////////////////////////////////////////////
//功能：判断一个数组中是否已经拥有要检测的值。
//参数：
//    value:待检测值
//    array[]:待检测数组
//    arLength:数组长度
bool IsHaved(int value,int array[],int arLength)
{
for(int i=0;i<arLength;i++)
{
if(array[i]==value)
return true;
}
return false;
}

//功能：把一个值插入到一个数组中，替换给定的值。
//参数：
//    value:待插入值
//    array[]:待插入数组
//    arLength:数组长度
//   replacedValue:要替换的值，即见此值便覆盖，然后插入结束返回true。如果没有此值则返回false
//备注：插入后数组并没有排序，只是替换了从头出现的第一个被替换值。
bool InsertValToAr(int value,int array[],int arLength,int replacedValue)
{
for(int i=0;i<arLength;i++)
{
if(array[i]==replacedValue)
{
array[i]=value;
return true;
}
}
return false;
}

//功能：把一个数组中的所有的值插入到另一个数组中，替换给定的值。
//参数：
//    ar[]:待插入数组
//    insertedAr[]:被插入数组
//    arLength:待插入数组长度
//    insertedArLength:被插入数组长度
//   replacedValue:被替换的值
//备注：把ar中的所有值插入到insertedAr中，替换其中的值为replacedValue的元素。插入成功返回true,失败返回false.

bool InsertArToAr(int ar[],int insertedAr[],int arLength,int insertedArLength,int replacedValue)
{
if(insertedArLength < arLength)
return false;
for(int i=0;i<arLength;i++)
{
if(!IsHaved(ar[i],insertedAr,insertedArLength))
if(! InsertValToAr(ar[i],insertedAr,insertedArLength,replacedValue))
return false;
}
return true;
}

//两个数组的并，将合并后的值放入第二个数组中。等于InsertArToAr
bool MergeAr(int ar[],int insertedAr[],int arLength,int insertedArLength,int replacedValue)
{
if(insertedArLength < arLength)
return false;
for(int i=0;i<arLength;i++)
{
if(!IsHaved(ar[i],insertedAr,insertedArLength))
if(! InsertValToAr(ar[i],insertedAr,insertedArLength,replacedValue))
return false;
}
return true;
}

//功能：两个数组的差，结果赋给被减数组。
//参数：
//    minusedAr[]:被减数组
//    minusAr[]:减数数组
//    minusedArLength:被减数数组长度
//    minusArLength:减数组长度
//   defaultValue:默认值
//备注：把ar中的所有值插入到insertedAr中，替换其中的值为replacedValue的元素。插入成功返回true,失败返回false.
void MinusAr(int minusedAr[],int minusAr[],int minusedArLength,int minusArLength,int defaultValue)
{
for(int i=0;i<minusedArLength;i++)
{
if(IsHaved(minusedAr[i],minusAr,minusArLength))
minusedAr[i]=defaultValue;
}
}

//功能：判断一个数组是否只用默认值组成。
//参数：
//    ar[]:待检测数组
//    arLength:待检测数组长度
//   replaceValue:默认值
bool IsEmptyAr(int ar[],int arLength,int defaultValue)
{
for(int i=0;i<arLength;i++)
{
if(ar[i]!=defaultValue)
return false;
}
return true;
}

//功能：清空一个数组，替换成给定的值。
//参数：
//    ar[]:待清空数组
//    arLength:待清空数组长度
//   replaceValue:替换的值
void ClearArray(int ar[],int arLength,int replaceValue)
{
for(int i=0;i<arLength;i++)
{
ar[i]=replaceValue;
}
}

//功能：打印数组中所有的值，值与值之间用空格隔开
//参数：
//    ar[]:待打印数组
//    arLength:待打印数组长度
void PrintArray(int ar[],int arLength)
{
for(int i=0;i<arLength;i++)
cout << ar[i] << " ";
cout << endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////

//当操作符为'E'时更新数组except，把所有比较两边的值都加入到except中
void UpdateEwhenE(int ar[],int arlength)
{
InsertArToAr(ar,except,arlength,exceptLength,0);
}

//当操作符为'H','L'时更新数组except，把不属于比较两边的所有值加入到except中。
void UpdateEwhenHorL(int ar1[],int ar2[],int arLength)
{
for(int i=1;i<=totalNum;i++)
{
if(!IsHaved(i,ar1,arLength) && !IsHaved(i,ar2,arLength) && !IsHaved(i,except,exceptLength))
InsertValToAr(i,except,exceptLength,0);
}
}

//调试用打印
void debugPrintSupandInf()
{
cout << "superM=";
PrintArray(superM,maxLengthOfGroup);
cout << "inferM=";
PrintArray(inferM,maxLengthOfGroup);
cout << "except=";
PrintArray(except,exceptLength);
}

//当操作符为'E'时需要进行的操作。
void CompareE(int i,Group cgroup)
{
UpdateEwhenE(cgroup.group[i*2],cgroup.numOfOG);
UpdateEwhenE(cgroup.group[i*2+1],cgroup.numOfOG);

//debugPrintSupandInf();
}

//找出把两个数组中相同值，情况数组1然后把相同的值赋于数组1
void updateInSameA(int ar1[],int ar2[],int ar1Length,int ar2Length)
{
//cout << "into updateInSameA" <<endl;
int tmp[maxLengthOfGroup]={0};
for(int i=0;i<ar2Length;i++)
{
if(IsHaved(ar2[i],ar1,ar1Length))
{
InsertValToAr(ar2[i],tmp,maxLengthOfGroup,0);
}
}

ClearArray(ar1,ar1Length,0);
InsertArToAr(tmp,ar1,maxLengthOfGroup,ar1Length,0);
}

//当操作符为'H'时需要进行的操作。
void CompareH(int i,Group cgroup)
{
UpdateEwhenHorL(cgroup.group[i*2],cgroup.group[i*2+1],cgroup.numOfOG);
if(!hOrL)
{
//cout << "into !hOrL" << endl;

InsertArToAr(cgroup.group[i*2],superM,cgroup.numOfOG,maxLengthOfGroup,0);
InsertArToAr(cgroup.group[i*2+1],inferM,cgroup.numOfOG,maxLengthOfGroup,0);
hOrL=true;

//debugPrintSupandInf();

}
else
{
//cout << "into hOrL" << endl;

updateInSameA(superM,cgroup.group[i*2],maxLengthOfGroup,cgroup.numOfOG);
updateInSameA(inferM,cgroup.group[i*2+1],maxLengthOfGroup,cgroup.numOfOG);

//debugPrintSupandInf();
}
}

//当操作符为'L'时需要进行的操作。
void CompareL(int i,Group cgroup)
{
UpdateEwhenHorL(cgroup.group[i*2],cgroup.group[i*2+1],cgroup.numOfOG);
if(!hOrL)
{
//cout << "into !hOrL" << endl;

InsertArToAr(cgroup.group[i*2],inferM,cgroup.numOfOG,maxLengthOfGroup,0);
InsertArToAr(cgroup.group[i*2+1],superM,cgroup.numOfOG,maxLengthOfGroup,0);
hOrL=true;

//debugPrintSupandInf();

}
else
{
//cout << "into hOrL" << endl;

updateInSameA(inferM,cgroup.group[i*2],maxLengthOfGroup,cgroup.numOfOG);
updateInSameA(superM,cgroup.group[i*2+1],maxLengthOfGroup,cgroup.numOfOG);

//debugPrintSupandInf();

}
}

//结果打印
void ResultPrint(Group cgroup)
{
int resultID;
char resultCode;
cout << caseNum << " " << totalNum << " "<< operation[0] << operation[1] << operation[2] << " ";
if(!hOrL)
//如果从来没有出现'H'或'L'则没有MWM
{
resultID=0;
resultCode='m';
}
else if( IsEmptyAr(superM,maxLengthOfGroup,0) &&  IsEmptyAr(inferM,maxLengthOfGroup,0) )
//如果出现过'H'或'L'，并且最终superM和inferM都被消空了。则说明出现矛盾。
{
resultID=-1;
resultCode='f';
}
else if(!IsEmptyAr(superM,maxLengthOfGroup,0))
//如果没有矛盾则根据我们分的组肯定能找出MWM，而且唯一
{
for(int i=0;i<maxLengthOfGroup;i++)
{
if(superM[i]!=0)
{
resultID=superM[i];
break;
}
}
resultCode='s';
}
else
{
for(int i=0;i<maxLengthOfGroup;i++)
{
if(inferM[i]!=0)
{
resultID=inferM[i];
break;
}
}
resultCode='i';
}
cout << resultID << " " << resultCode << endl;
for(int i=0;i<operationNum;i++)
{
for(int j=0;j<cgroup.numOfOG;j++)
{
cout << cgroup.group[i*2][j] << " ";
}
cout << operation[i] << " ";
for(int j=0;j<cgroup.numOfOG;j++)
{
cout << cgroup.group[i*2+1][j] << " ";
}
cout << endl;
}
}

//初始化
void init()
{
ClearArray(except,exceptLength,0);
ClearArray(superM,maxLengthOfGroup,0);
ClearArray(inferM,maxLengthOfGroup,0);
hOrL=false;
}

void Compare(Group cgroup)
{
//cgroup.print();
init();
for(int i=0;i<3;i++)
{
char ch=operation[i];
if(ch=='E')
{
//cout << "into E" << endl;

CompareE(i,cgroup);
}
else if(ch=='H')
{
//cout << "into H" << endl;

CompareH(i,cgroup);
}
else if(ch=='L')
{
//cout << "into L" << endl;

CompareL(i,cgroup);
}
}
MinusAr(superM,except,maxLengthOfGroup,exceptLength,0);
MinusAr(inferM,except,maxLengthOfGroup,exceptLength,0);

/*
cout << "into minusAr superM" << endl;
cout << "into minusAr superS" << endl;
debugPrintSupandInf();
*/

ResultPrint(cgroup);
}

//选择使用哪种情况的分组
void SelectGroup()
{
switch(totalNum)
{
case 8:Compare(group8);break;
case 9:Compare(group9);break;
case 10:Compare(group10);break;
case 11:Compare(group11);break;
case 12:Compare(group12);break;
}
}

//读取文件
{
ifstream OpenFile("spot.in");
//打开文件,注意如果使用kylix则需要写完整地路径值
OpenFile >> caseNum;
while(!OpenFile.eof() && caseNum!=0)
//eof()函数用来判断文件的结束，规定 # 为input的结束
{
//cout << "caseNum=" << caseNum << endl;
OpenFile >> totalNum;
for(int i=0;i<3;i++)
OpenFile >> operation[i];
//这里不能使用 OpenFile.get(operation[i])代替，因为get(ch)函数不会忽略空格，致使operatio[1]=' '
//cout << "totalNum=" << totalNum <<endl;
//cout << "operation=" << operation[0] << operation[1] << operation[2] << endl;
SelectGroup();
OpenFile >> caseNum;
}
OpenFile.close();
//关闭文件资源
}

void main()
{