超级测谎机。

注:本文100%原创!

一、问题描述:

在某个镇某个夜晚,发生一起谋杀案,警察通过排查确定杀人凶手是4个嫌疑中的一个,以下是四个人的说词

A说:不是我

B说:是C

C说:是D

D说:C在胡说

其中只有3个人说了真话,1个人说了假话,现在根据这些信息,写一个程序来确定哪个是凶手。

二、问题分析

可以直接写死程序,但为了更加好玩,把程序写活,就得换另外一种思维了。有用户手动输入说话内容,然后根据内容来分析结果,输出。这里采用预备存储法,即根据用户的输入,预先得出有多少种可能的结果,然后再从中判断,最后输出。

三、涉及知识点

排列组合,动态数组,C语言简单操作。

四、举例分析

A说:不是我

B说:是C

C说:是D

D说:C在胡说

假如:用某个人说话的内容用大小写字母表示。小写字母表示凶手不是自己,大写字母表示凶手就是自己,即a表示,A是不是凶手,A表示A是凶手。所以案例输入应该为:

A说:a

B说:C

C说:D

D说:d

根据排列组合知识,得知:4个人,如果有3个人说真话,即从4个人中选择3个人出来(说真话的),或者从4个人中选择1个人出来(说假话),这里以说真话为例。所以为C(4,3)=4。

所以说话真假的矩阵也可以是:

ABCd  (d说假话)

ABcD(c说假话)

AbCD(b说假话)

aBCD(a说假话)

我们定义一个result数组,用来判断最终结果。如果我们这样,如果某个人的说话内容是A,那么对应result[0]就+1,0对应A,1对应b......, 如果某个人的说话内容是a,那么result[1]+1, result[2]+1, reuslt[3]+1, 即result[0]不加,最终根据result[i]的数值大小来判断,如果result[i]等于总人数,那么第i号人就是凶手,可能有多种情况,然后转换成判断矩阵来计算。

五、运行效果图

案例测试:手动计算只有一种结果

换一种测试:说话内容不变,说真话人数变为2个,手动计算知道有两种结果

再换一种测试,7个人,5个说真话的,

其他的不演示了,因为人数越多越不好验证 ,数学系的同学深有体会!

下面附上代码,其中有包含了排列组合的代码

六、代码

C语言代码如下:

#include <stdio.h>

#include <stdlib.h>

int cNumber(int n, int m);

int combine(int n, int m, char *tell);

char correct(char arr, char tell);

int check(int n, char *tell, char *people, int *result);

int main(void)

{

    int m, n;

    printf("请输入测试者人数:");

    scanf("%d", &n);

    printf("请输入说真话的人数:");

    scanf("%d", &m);

    char *tell = calloc(n, sizeof(char));

    printf("请输入说话内容(假如X是凶手,请输入X, 否则请输入x)\n");

    for(int i=0; i<n; i++)

    {

        printf("%c说的话:", 'A'+i);

        getchar();      //清空缓冲区

        scanf("%c", &tell[i]);

    }

    printf("\n测谎开始!\n\n");

    combine(n, m, tell);

    return 0;

}

//计算组合数种类

int cNumber(int n, int m)

{

    int i, tmp=1, group=1;

    for(i=2; i<=m; i++)

    {

        tmp *= i;

    }

    for(i=0; i<m; i++)

    {

        group *= (n-i);

    }

    return group/tmp;

}

//纠正原话的结果

char correct(char show, char tell)

{

    if(show>='A' && show<='Z')    //说真话

    {

        return tell;              //返回原话

    }

    else if(tell>='A' && tell<='Z')

    {

        return tell+'a'-'A';      //返回原话的反话

    }

    else

    {

        return tell-('a'-'A');    //返回原话的反话

    }

}

//检测出结果

int check(int n, char *tell, char *people, int *result)

{

    int i, j, k;

   

    for(i=0; i<n; i++)

    {

        result[i] = 0;

    }

    for(i=0; i<n; i++)

    {

        for(j=0; j<n; j++)

        {

            if(tell[i] == people[j])       //直接说是people[j]

            {

                result[j]++;               //people[j]怀疑性加一

                break;

            }

            else if(tell[i]>='a' && tell[i]<='z' && (tell[i]- ('a'-'A')) == people[j])    //说不是people[j]

            {

                for(k=0; k<n; k++)

                {

                    if(k!=j)

                    {

                        result[k]++;        //除了people[i]外的人怀疑性加一

                    }

                }

                break;

            }

        }

    }

    //当且仅当只有一个result[i]==n时,检测结果合理

    for(i=0, j=0 ; i<n; i++)

    {

        if(result[i]==n)

        {

            k=i;       //记录凶手编号

            j++;       //假如检测出有多个凶手

        }

      //printf("result[%d]=%d, ", i, result[i]);

    }

   

    if(j==1)

    {

        printf("\n测试结果: 凶手是%c!\n", people[k]);

        return 1;

    }

   

    return 0;

}

int combine(int n, int m, char *tell)

{

    int i, j, k, count, group;

    group = cNumber(n, m);

    char **show = calloc(group, sizeof(char*));   //用来存储所有可能情况

    for(i=0; i<group; i++)

    {

        show[i] = calloc(n, sizeof(char));

    }

    for(i=0; i<group; i++)

    {

        for(j=0; j<n; j++)

        {

            show[i][j] = 'a'+ j;

        }

    }

    if(n<m || m<1)

    {

        printf("输入组合数非法!\n");

        return -1;

    }

    char *people = calloc(n, sizeof(char));   //用来存储有多少个人

    for(int i=0; i<n; i++)     //填充索引,有多少个

    {

        people[i] = i+'A';

    }

    int *a = calloc(m, sizeof(int));  //用来存储每次产生的一种组合

    for(i=0; i<m; i++)  //第一种组合,

    {

        a[i] = i+1;

    }

    for(j=m, count=0; a[0]<=(n-m+1);)  //当为最后一种组合时,循环结束

    {

        for(;a[m-1]<=n; a[m-1]++)  //最后一位不断递增,直到达到最大值,产生进位

        {

            count++;

            //printf("第%d种组合: ", count);    //计算组合数种类

            for(k=0; k<m; k++)

            {

                //printf("%c", arr[a[k]-1]);

                show[count-1][people[a[k]-1]-'A'] = people[a[k]-1];

            }

            //printf("\n");  

        }

        for(j=m-2; j>=0; j--)  //判断a[1]--a[m-2]是否有进位

        {

            a[j]++;

            if(a[j] <= (j+n-m+1))  //a[j]不进位,a[j-1]也不进位

            {

                break;

            }

        }

        for(j++; j>0 && j<m; j++)   //调整,使得a[index-1],a[index]顺序排列

        {

            a[j] = a[j-1] + 1;

        }

    }

    int *result = calloc(n, sizeof(int));

    char *correct_tell = calloc(n, sizeof(char));

    //计算所有组合情况对应的结果

    for(i=0; i<group; i++)

    {

        for(j=0; j<n; j++)

        {

            correct_tell[j] = correct(show[i][j], tell[j]);

            //printf("correct_tell[%d]=%c ", j, correct_tell[j]);

        }

        k = check(n, correct_tell, people, result);

        if(k==1)

        {

            for(k=0; k<n; k++)

            {

                //printf("show[%d][%d]=%c  ", i, k , show[i][k]);

                if(show[i][k]>='A' && show[i][k]<='Z')

                {

                    printf("%c说真话", people[k]);

                }

                else

                {

                    printf("%c说假话", people[k]);

                }

                printf("\n");

            }

        }

        //printf("\n");

    }

    //释放堆内存

    for(i=0; i<group; i++)

    {

        free(show[i]);

    }

    free(show);

    free(people);

    free(result);

    free(correct_tell);

    free(a);

    getchar();

    return 0;

}

当然本次的测谎机有一点的局限性,人数最多26个,很显然的,当然可以修改;用户需要判断说话内容来输入;没有对用户的输入做太多合法性判断;当无法确定凶手时,无法输出,只能判断只有一个凶手的情况,不能判断出团伙作案的情况。

感兴趣的小伙伴可以点个关注哦,下次改造成语音识别的,做个真正的测谎机!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
我们的皮肤很棒!它提供了一种让我们体验触摸感的媒介,它可以防止感染并保持内脏,但是我敢打赌,您不知道我们的皮肤会根据许多不同的事物改变导电性,这就是我们的心情!它称为皮肤电活动(EDA),您可以在此处阅读一个非常有趣的Wikipedia页面。基本原理是我们的皮肤会根据我们的感觉改变其导电性。 我们首先将Arduino连接到主题,然后将Arduino连接到带有绘图软件的计算(我将在后面详细介绍) 首先,我们要问这个问题一些简单的问题,我们知道他们会如实回答“你叫什么名字”和“你住在哪里”来获得基线,然后我们就可以开始询问他们可能会谎的问题,如果他们这样做,他们可能会感到紧张,然后我们可以阅读他们谎的基线的变化:D 我们需要Aruino Nano,一些LED,维可牢尼龙搭扣,2K电阻器以及一些基本工具,例如纸板,铝箔,热胶,烙铁和工艺刀。 接线非常简单,我们将按以下顺序连接它们: 将长电缆连接到Arduino模拟引脚0 将2k电阻接地并连接扩展的模拟0引脚 将长电缆连接到Arduino 5伏引脚 将绿色LED的阳极(长脚)连接到引脚2,将阴极(短脚)接地 将橙色LED的阳极连接到引脚3,将阴极接地 将红色LED的阳极连接到引脚4,阴极接地 这就是Arduino的所有接线,现在我们需要一种将传感器接线保持在手指上的方法,我们将在稍后进行介绍。 我们将要使用的主要软件是Arduino IDE上的最新版本。新的更新带来了一种新的方式来查看从Arduino接收的数据,而不再是来自串行监视器的文本形式,它现在可以实时图形显示,这将有助于我们识别数据何时更改其模式(当有人谎时) 要打开绘图仪,请打开Arduino并导航至工具菜单,您应该在串行监视器下方看到它。 现在,微控制器的代码在下面的代码部分中。复制并将其上传到您的电路板上。 现在已经完成了项目的基本形式,我们可以开始添加功能以使其易于使用,我们将开始添加手指夹以保持手指与电缆之间的稳定连接。让我们先将一块锡箔胶粘到一条魔术贴的底部,然后对两块魔术贴(钩子和环子)进行此操作。现在将其绕到手指上,直到紧密贴合(检查照片),然后用胶带将从模拟引脚0到锡箔的裸线,然后对5伏引脚重复此步骤(确保连接良好) 我们需要做的最后一件事是将电子设备放在外壳中,首先将arduino和所有电线粘在6cm的一侧,然后将扩展的电线(引脚模拟0和5伏)连接到矩形的另一侧(9cm)侧)。现在将三个led胶粘到我们在6x5cm矩形上制作的孔上,并进行测试,如果一切顺利,您应该有一个小型便携式Arduino测谎仪,但是我提醒您,这不是最真实的测谎仪使用的最准确的系统许多其他传感器来确定是否有人在撒谎,例如心率监测仪和其他人,我的意思是不要将其结果用于严重问题.
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值