网友聚会解答

来源:互联网 发布:c语言的发展前景 编辑:程序博客网 时间:2024/04/30 03:39
 
网友聚会
某论坛想组织一次小规模的网友聚会,邀请论坛的n(1<=n<=4)个版主和论坛上m(1<=m<=10)个积极的网友参加。这m个网友是根据在论坛上的发文贡献从大到小排列后选出来的。组织者在论坛上公布了聚会计划,也按贡献大小公布了这m个网友的名单,然后逐个向这m个网友询问参加意向。有趣的是,这些网友都没有直接说参加还是不参加,而是声明了各自参加聚会的条件,而且这些条件只和版主以及贡献比自己大的那些网友是否参加有关。
组织者统计了一下,各种条件其实可以归纳为4类,每一类都和另外一个或两个人是否参加有关。如果用X和Y来表示某个版主或者某个网友,那么这4类条件是:
1) 我不参加,除非X和Y都参加。
2) 我参加,除非X和Y都不参加。
3) 如果X参加,那么我不参加,否则我参加。
4) 我参加,除非X去并且Y不去。
组织者发现,对于以上各类条件,只要确定了条件中X和Y是否参加,那么该网友是不是参加也就确定了。因此在上述4类条件下,该网友是否参加可分别用逻辑表达式X v Y、X ^ Y、~X和X > Y来表示,其中4个符号分别表示析取、合取、否定和推演。
组织者还发现,虽然各个论坛版主是否会参加聚会还不确定,但是根据各个网友声明的参加条件进行推理,其实有些网友一定不会参加聚会,而有些网友一定会参加聚会,当然还有一些网友是否参加最终要看各个版主的参加情况。
组织者请你写一个程序,由他输入各个网友声明的条件,请你输出各个网友的参加情况。输入格式是这样的:用P0、P1、…、Pn-1分别表示各个版主,用A0、A1、…、Am-1分别表示各个网友,且下标越小表示该网友贡献越大。程序的输入有多行,第一行是以空格分开的两个整数n和m,之后的m行依次描述各个网友声明的条件,并严格依照以下格式:
Ai空格Tj空格?空格Sk
其中Ai依次为A0、A1、…、Am-1;?可以为“~”、“>”、“^”或“v”之一;若?为“~”,则Tj为“X0”(表示只与后面Sk的参加情况有关),若?为“>”、“^”或“v”,则Tj为Aj(0<=j<i)或Pj(0<=j<n);Sk为Ak(0<=k<i)或Pk(0<=k<n)。
程序的输出要求是以空格分开的m个整数(最后一个整数之后没有空格直接换行),分别表示A0、A1、…、Am-1的参加情况。不管各位版主的参加情况如何,如果该网友一定会参加聚会则用1表示,如果该网友一定不会参加聚会则用-1表示,如果必须根据版主的参加情况才能确定则用0表示。
【输入样例1】
1 2
A0 X0 ~ P0
A1 A0 v P0
【输出样例1】
0 1
【输入样例2】
3 4
A0 P0 > P1
A1 P1 > P2
A2 P2 > P3
A3 P0 > P3
【输出样例2】
0 0 0 0
【输入样例3】
2 3
A0 P0 > P1
A1 P1 > A0
A2 X0 ~ A1
【输出样例3】
0 1 -1

 #include <iostream>
using namespace std;

struct Condition
{
 char type; // 逻辑运算符
 char left; // 左项,X或P或A
 int i;  // 左项下标
 char right; // 右项,P或A
 int j;  // 右项下标
 bool value; // 真假的取值
};
Condition A[10]; // 记录表达式情况
int TrueTimes[10] = {0}; // 记录取真次数
bool P[4];  // 变元

void SetP(int i) // 枚举版主参加情况
{
 P[0] = bool(i & 0x1);
 P[1] = bool(i & 0x2);
 P[2] = bool(i & 0x4);
 P[3] = bool(i & 0x8);
}

bool LeftValue(const Condition &a) // 左项取值
{
 if (a.left == 'A')
  return A[a.i].value;
 else
  return P[a.i];
}

bool RightValue(const Condition &a) // 右项取值
{
 if (a.right == 'A')
  return A[a.j].value;
 else
  return P[a.j];
}

int OutValue(int allTimes, int trueTimes)
{
 if (trueTimes == 0)
  return -1;
 if (trueTimes == allTimes)
  return 1;
 return 0;
}

int main()
{
 int n, m;  // 读入n, m
 cin >> n >> m;

 char c;   // 辅助用
 for (int i = 0; i < m; i++)  // 读入m个逻辑表达式
  cin >> c >> c >> A[i].left >> A[i].i
  >> A[i].type >> A[i].right >> A[i].j;

 int allTimes = 1 << n; // 先计算总的枚举次数

 for (int i = 0; i < allTimes; i++)
 {  
  SetP(i); // 枚举版主参加情况

  // 依次计算网友参加情况
  for (int j = 0; j < m; j++)
  {
   switch (A[j].type)
   {
    case '~':
     A[j].value = !RightValue(A[j]);
     break;
    case '>':
     A[j].value = !LeftValue(A[j]) || RightValue(A[j]);
     break;
    case '^':
     A[j].value = LeftValue(A[j]) && RightValue(A[j]);
     break;
    case 'v':
     A[j].value = LeftValue(A[j]) || RightValue(A[j]);
     break;
   }
   if (A[j].value)  // 参加聚会
    TrueTimes[j] ++;
  }
 }

 cout << OutValue(allTimes, TrueTimes[0]);
 for (int i = 1; i < m; i++)
  cout << ' ' << OutValue(allTimes, TrueTimes[i]);
 cout << endl;
 
 return 0;
}

原创粉丝点击