蓝桥杯 算法提高 判断名次 求助~!

Get *null 2016-01-26 04:57:28
算法提高 判断名次
时间限制:1.0s 内存限制:256.0MB

问题描述
  某场比赛过后,你想要知道A~E五个人的排名是什么,于是要求他们每个人说了一句话。(经典的开头……-_-!)得了第1名的人23,说了假话;得了第5名的人不好意思,也说了假话;为了使求解问题简单,第3名同样说了假话。(奇数名次说假话)
输入格式
  共5行,各行依次表示A~E说的话。
  每行包含一个形如“A>=3”的名次判断,即一个大写字母+关系运算符+一个数字,不包含空格。
  大写字母A~E,关系运算<、<=、=、>=、>、!=,数字1~5。注意:等于是“=”不是“==”!
输出格式
  可能有多解,请按照字典序输出排名序列,每个解一行
  最后一行输出解的数量
样例输入
A=2
D=5
E>3
A>2
B!=1
样例输出
ACDEB
AECBD
BADCE
BCADE
BDACE
CEADB
CEBDA
7


我的代码是用a[0],a[1],a[2],a[3],a[4]分别表示A,B,C,D,E的名次,s1表示谎话数,s2表示真话数。
#include<stdio.h>
#include<string.h>
int a[5],s1,s2,sum=0,p;
bool judge(char *str)
{
if(str[1]=='<'&&str[2]>='1'&&str[2]<='9')
{
if(a[str[0]-'A']<str[2]-'0')
return 1;
}
if(str[1]=='<'&&str[2]=='=')
{
if(a[str[0]-'A']<=str[3]-'0')
return 1;
}
if(str[1]=='=')
{
if(a[str[0]-'A']==str[2]-'0')
return 1;
}
if(str[1]=='>'&&str[2]=='=')
{
if(a[str[0]-'A']>=str[3]-'0')
return 1;
}
if(str[1]=='>'&&str[2]>='1'&&str[2]<='9')
{
if(a[str[0]-'A']>str[2]-'0')
return 1;
}
if(str[1]=='!'&&str[2]=='=')
{
if(a[str[0]-'A']!=str[3]-'0')
return 1;
}
return 0;
}
int main()
{
char ans[5][10],saying[5][10];
memset(ans,0,sizeof(ans));
memset(saying,0,sizeof(saying));
for(int i=0; i<5; i++)
gets(saying[i]);
for(a[0]=1; a[0]<=5; a[0]++)
{
for(a[1]=1; a[1]<=5; a[1]++)
{
if(a[1]==a[0])
continue;
for(a[2]=1; a[2]<=5; a[2]++)
{
if(a[2]==a[0]||a[2]==a[1])
continue;
for(a[3]=1; a[3]<=5; a[3]++)
{
if(a[3]==a[0]||a[3]==a[1]||a[3]==a[2])
continue;
for(a[4]=1; a[4]<=5; a[4]++)
{
if(a[4]==a[0]||a[4]==a[1]||a[4]==a[2]||a[4]==a[3])
continue;
s1=0,s2=0;
if(judge(saying[0]))
s2++;
else if(a[0]%2==1)
s1++;
if(judge(saying[1]))
s2++;
else if(a[1]%2==1)
s1++;
if(judge(saying[2]))
s2++;
else if(a[2]%2==1)
s1++;
if(judge(saying[3]))
s2++;
else if(a[3]%2==1)
s1++;
if(judge(saying[4]))
s2++;
else if(a[4]%2==1)
s1++;
if(s1==3&&s2==2)
{
for(p=0; p<5; p++)
if(a[p]==1)
ans[sum++][0]='A'+p;
for(p=0; p<5; p++)
if(a[p]==2)
ans[sum-1][1]='A'+p;
for(p=0; p<5; p++)
if(a[p]==3)
ans[sum-1][2]='A'+p;
for(p=0; p<5; p++)
if(a[p]==4)
ans[sum-1][3]='A'+p;
for(p=0; p<5; p++)
if(a[p]==5)
ans[sum-1][4]='A'+p;
}
}
}
}
}
}
char tmp[10];
for(int i=0; i<sum; i++)//字典序排列
for(int j=i+1; j<sum; j++)
{
if(strcmp(ans[i],ans[j])>0)
{
strcpy(tmp,ans[i]);
strcpy(ans[i],ans[j]);
strcpy(ans[j],tmp);
}
}
for(int i=0; i<sum; i++)
printf("%s\n",ans[i]);
printf("%d\n",sum);
return 0;
}








然而还是有两组数据过不了,第一组闪退,第二组错误。
input1:
A=2

D=5

E>3

A>2

B!=1

output2:
ACDEB

AECBD

BADCE

BCADE

BDACE

CEADB

CEBDA

7

input2:
C<=3

A=1

B=1

E>=4

D!=2

output2:
AEDBC

BDACE

BEACD

BEDCA

CDBAE

CEBAD

CEDAB

DECAB

8
...全文
708 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
china丶龙少 2019-01-08
  • 打赏
  • 举报
回复
引用 8 楼 china丶龙少 的回复:
#include <iostream>
#include <cstring>
using namespace std;

int a[5], s1, s2, sum = 0;

bool judge(char *str)
{
if(str[1] == '<' && str[2] >= '1' && str[2] <= '9')
{
if(a[str[0]-'A'] < str[2]-'0')
return 1;
}
if(str[1] == '<' && str[2] == '=')
{
if(a[str[0]-'A'] <= str[3]-'0')
return 1;
}
if(str[1] == '=')
{
if(a[str[0]-'A'] == str[2]-'0')
return 1;
}
if(str[1] == '>' && str[2] == '=')
{
if(a[str[0]-'A'] >= str[3]-'0')
return 1;
}
if(str[1] == '>' && str[2] >= '1' && str[2] <= '9')
{
if(a[str[0]-'A'] > str[2]-'0')
return 1;
}
if(str[1] == '!' &&str[2] == '=')
{
if(a[str[0]-'A'] != str[3]-'0')
return 1;
}
return 0;
}

/*
C<=3
A=1
B=1
E>=4
D!=2
*/

int main()
{
char ans[20][10], saying[5][10];

memset(ans, 0, sizeof(ans));
memset(saying, 0, sizeof(saying));

for(int i = 0; i < 5; i++)
{
cin >> saying[i];
}

for(a[0] = 1; a[0] <= 5; a[0]++)
{
for(a[1] = 1; a[1] <= 5; a[1]++)
{
if(a[1] == a[0])
continue;
for(a[2] = 1; a[2] <= 5; a[2]++)
{
if(a[2] == a[0] || a[2] == a[1])
continue;
for(a[3] = 1; a[3] <= 5; a[3]++)
{
if(a[3] == a[0] || a[3] == a[1] || a[3] == a[2])
continue;
for(a[4] = 1; a[4] <= 5; a[4]++)
{
if(a[4] == a[0] || a[4] == a[1] || a[4] == a[2] || a[4] == a[3])
continue;
//如果没有重复
s1 = 0, s2 = 0;

for(int i = 0; i < 5; i++)
{
if(judge(saying[i]))
s2++;
else if(a[i] % 2)
s1++;
}

if(s1 == 3 && s2 == 2)
{
for(int i = 0; i < 5; i++)
if(a[i] == 1)
ans[sum++][0] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 2)
ans[sum-1][1] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 3)
ans[sum-1][2] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 4)
ans[sum-1][3] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 5)
ans[sum-1][4] = 'A' + i;
}
}
}
}
}
}

char tmp[10];
for(int i = 0; i < sum - 1; i++)//字典序排列
for(int j = 0; j < sum - 1 - i; j++)
{
if(strcmp(ans[j], ans[j+1]) > 0)
{
strcpy(tmp, ans[j]);
strcpy(ans[j], ans[j+1]);
strcpy(ans[j+1], tmp);
}
}

for(int i = 0; i < sum; i++)
cout << ans[i] << endl;
cout << sum << endl;

return 0;
}

我改了以下,100分了
china丶龙少 2019-01-08
  • 打赏
  • 举报
回复
#include <iostream>
#include <cstring>
using namespace std;

int a[5], s1, s2, sum = 0;

bool judge(char *str)
{
if(str[1] == '<' && str[2] >= '1' && str[2] <= '9')
{
if(a[str[0]-'A'] < str[2]-'0')
return 1;
}
if(str[1] == '<' && str[2] == '=')
{
if(a[str[0]-'A'] <= str[3]-'0')
return 1;
}
if(str[1] == '=')
{
if(a[str[0]-'A'] == str[2]-'0')
return 1;
}
if(str[1] == '>' && str[2] == '=')
{
if(a[str[0]-'A'] >= str[3]-'0')
return 1;
}
if(str[1] == '>' && str[2] >= '1' && str[2] <= '9')
{
if(a[str[0]-'A'] > str[2]-'0')
return 1;
}
if(str[1] == '!' &&str[2] == '=')
{
if(a[str[0]-'A'] != str[3]-'0')
return 1;
}
return 0;
}

/*
C<=3
A=1
B=1
E>=4
D!=2
*/

int main()
{
char ans[20][10], saying[5][10];

memset(ans, 0, sizeof(ans));
memset(saying, 0, sizeof(saying));

for(int i = 0; i < 5; i++)
{
cin >> saying[i];
}

for(a[0] = 1; a[0] <= 5; a[0]++)
{
for(a[1] = 1; a[1] <= 5; a[1]++)
{
if(a[1] == a[0])
continue;
for(a[2] = 1; a[2] <= 5; a[2]++)
{
if(a[2] == a[0] || a[2] == a[1])
continue;
for(a[3] = 1; a[3] <= 5; a[3]++)
{
if(a[3] == a[0] || a[3] == a[1] || a[3] == a[2])
continue;
for(a[4] = 1; a[4] <= 5; a[4]++)
{
if(a[4] == a[0] || a[4] == a[1] || a[4] == a[2] || a[4] == a[3])
continue;
//如果没有重复
s1 = 0, s2 = 0;

for(int i = 0; i < 5; i++)
{
if(judge(saying[i]))
s2++;
else if(a[i] % 2)
s1++;
}

if(s1 == 3 && s2 == 2)
{
for(int i = 0; i < 5; i++)
if(a[i] == 1)
ans[sum++][0] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 2)
ans[sum-1][1] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 3)
ans[sum-1][2] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 4)
ans[sum-1][3] = 'A' + i;
for(int i = 0; i < 5; i++)
if(a[i] == 5)
ans[sum-1][4] = 'A' + i;
}
}
}
}
}
}

char tmp[10];
for(int i = 0; i < sum - 1; i++)//字典序排列
for(int j = 0; j < sum - 1 - i; j++)
{
if(strcmp(ans[j], ans[j+1]) > 0)
{
strcpy(tmp, ans[j]);
strcpy(ans[j], ans[j+1]);
strcpy(ans[j+1], tmp);
}
}

for(int i = 0; i < sum; i++)
cout << ans[i] << endl;
cout << sum << endl;

return 0;
}
Get *null 2016-05-09
  • 打赏
  • 举报
回复
谢谢各位!!
fly_dragon_fly 2016-02-01
  • 打赏
  • 举报
回复
直接全排列, 5!=120非常小,出来后还不需要排序, 大体框架如下,
void dfs(int d)
{
    if(d==5){
        for(int i=0;i<5;i++){
            int x =pos[i]&1,y=judge(i);//judge判断第i个人话为真或假, pos代表i的排名
            if(x^y) return;
        }
        puts(a);
        ++cnt;
        return;
    }
    for(int i=0;i<5;i++) if(!vis[i]){
        vis[i]=1;
        a[d] =i+'A';
        pos[i] =d;
        dfs(d+1);
        vis[i] =0;
    }
}
lm_whales 2016-01-31
  • 打赏
  • 举报
回复
引用 2 楼 lm_whales 的回复:
假话则取 ,反说话内容 只要调换两个操作数次序即可
哦这话说错了,请忽略 另一种方法是3人说谎,两人说实话 根据说话内容 判定名次,求出各种可能的组合。 然后排序输出 这种方法,判定复杂,但是待选情况较少,不需要遍历全排列
lm_whales 2016-01-31
  • 打赏
  • 举报
回复
穷举法具体做法: 对每个排列按照如下方法处理: 每个人说的话,可以看作表达式 做一个简单的表达式解析程序 ABCDE 作为变量名 12345 名次作为变量值 对A=2 这种关系表达式加以解析。 并根据说话人的身份(即名次,决定说的是真话还是假话), 对表达式的值加以肯定(值不变)或否定(取反) 对每一个名次的可能组合(一个排列) 测试是否这五句话, 全符合说话人的身份(即上面计算结果是否全真)。 这样,再写一个枚举全排列的函数,即可实现穷举法。
Philipyexushen 2016-01-31
  • 打赏
  • 举报
回复
感觉就是个DFS枚举,5种状态枚举也枚举不了多久,而且还有那么多限制条件 根据题设条件直接先框定ABCDE的各自枚举范围 然后直接写递归就好了,最好不要像你这样子写代码,看着挺乱的
lm_whales 2016-01-30
  • 打赏
  • 举报
回复
假话则取 ,反说话内容 只要调换两个操作数次序即可
lm_whales 2016-01-30
  • 打赏
  • 举报
回复
最笨的方法穷举法: 枚举所有名次(全排列),假设没有并列名次,根据,说话内容和说话真假的组合,判断该排列是否是一个可能的名次。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧