社区讨论
有趣的现象+警钟
灌水区参与者 3已保存回复 3
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @m261szvc
- 此快照首次捕获于
- 2024/10/12 19:03 去年
- 此快照最后确认于
- 2025/11/04 17:22 4 个月前
本条水帖感谢 @xiaoke2021 这位dalao的倾力相助,膜拜orz。
事情是这样的:
几个月前我在写关于字符串练习的时候,遇上了这样一道有趣的题:P1039 [NOIP2003 提高组] 侦探推理(可以先去读题)。
读完题目,很明显这是枚举。于是写出如下代码(也就用了几星期):
CPP几个月前我在写关于字符串练习的时候,遇上了这样一道有趣的题:P1039 [NOIP2003 提高组] 侦探推理(可以先去读题)。
读完题目,很明显这是枚举。于是写出如下代码(
#include<bits/stdc++.h>
using namespace std;
int i,j,k;
int m,n,p,lendy,s,ss;
int md,zz,jj,zf,zf1,f;
string name[30],zynr[110],dy;
string week[10]={"","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
int zylx[4][110];
int mm[50];//0:不确定;1:真;2:假
char c1;
int main()
{
cin>>m>>n>>p;
for(i=1;i<=m;i++)
cin>>name[i]; //读取姓名并打上数字标记
for(i=1;i<=p;i++){ //读入证言并处理
k=0;
cin>>dy; //读入姓名与冒号
lendy=dy.length();
dy.erase(lendy-1,1); //删除冒号
while(name[k]!=dy) k++;
c1=getchar(); //读入空格
getline(cin,zynr[i]); //读入证言
if(zynr[i][zynr[i].length()-1]=='\n') zynr[i].erase(zynr[i].length(),2);
if(zynr[i]=="I am guilty."){
zylx[1][i]=1;zylx[2][i]=k;zylx[3][i]=k; continue;
}
else if(zynr[i]=="I am not guilty."){
zylx[1][i]=2;zylx[2][i]=k;zylx[3][i]=k;continue;
} //处理1,2种情况
for(j=1;j<=m;j++){
if(zynr[i]==name[j]+" is guilty."){
zylx[1][i]=3;zylx[2][i]=k;zylx[3][i]=j;break;
}
else if(zynr[i]==name[j]+" is not guilty."){
zylx[1][i]=4;zylx[2][i]=k;zylx[3][i]=j;break;
}
} //处理3,4种情况
for(j=1;j<=7;j++)
if(zynr[i]=="Today is "+week[j]+'.'){
zylx[1][i]=5;zylx[2][i]=k;zylx[3][i]=j;break;
}//处理5种情况
}
for(j=1;j<=m;j++){ //列举罪犯
for(i=1;i<=7;i++){ //列举星期
for(k=1;k<=p;k++){
switch(zylx[1][k])
{
case 1:
s=zylx[2][k];
switch(mm[s])
{
case 0:
if(zylx[3][k]!=j)mm[s]=2;//不是罪犯却说自己是罪犯
else if(zylx[3][k]==j) mm[s]=1;
break;
case 1:
if(zylx[3][k]!=j) md=1;//矛盾
break;
case 2:
if(zylx[3][k]==j) md=1;//矛盾
}
break;
case 2:
s=zylx[2][k];
switch(mm[s])
{
case 0:
if(zylx[3][k]==j) mm[s]=2; //是罪犯说自己不是罪犯
else if(zylx[3][k]!=j) mm[s]=1;
break;
case 1:
if(zylx[3][k]==j) md=1;//矛盾
break;
case 2:
if(zylx[3][k]!=j) md=1;//矛盾
}
break;
case 3:
s=zylx[2][k];
switch(mm[s])
{
case 0:
if(zylx[3][k]!=j) mm[s]=2; //不是罪犯说别人是罪犯
else if(zylx[3][k]==j) mm[s]=1;
break;
case 1:
if(zylx[3][k]!=j) md=1;//矛盾
break;
case 2:
if(zylx[3][k]==j) md=1;//矛盾
}
break;
case 4:
s=zylx[2][k];
switch(mm[s])
{
case 0:
if(zylx[3][k]==j) mm[s]=2;//是罪犯说别人不是罪犯
else if(zylx[3][k]!=j) mm[s]=1;
break;
case 1:
if(zylx[3][k]==j) md=1;//矛盾
break;
case 2:
if(zylx[3][k]!=j) md=1;//矛盾
}
break;
case 5:
s=zylx[2][k];
switch(mm[s])
{
case 0:
if(zylx[3][k]!=i) mm[s]=2;//星期
else if(zylx[3][k]==i) mm[s]=1;
break;
case 1:
if(zylx[3][k]!=i) md=1;//矛盾
break;
case 2:
if(zylx[3][k]==i) md=1;//矛盾
}
}//判断类型
}
for(k=1;k<=m;k++){
if(mm[k]==1) zz++;
else if(mm[k]==2) jj++;
}
if(!md&&zz<=m-n&&jj<=n&&zf!=j){
zf=j;
ss++;
}
jj=zz=md=0; for(k=1;k<=m;k++) mm[k]=0;
}
}
if(ss==0) cout<<"Impossible";
else if(ss!=0&&ss!=1) cout<<"Cannot Determine";
else cout<<name[zf];
}
放进你谷评测机内,出了大问题:30pts。
调了很久,仍旧发现不了问题。甚至我下载了一组数据,发现了一个很奇特的情况:
数据如下:
2 2 4
HELLO
GUILTY
HELLO: What is your name?
GUILTY: I am GUILTY.
GUILTY: Are you guilty?
HELLO: I am not guilty.
正确答案:
Dev-C++运行答案:
洛谷IDE运行答案:
很正常对吧?
评测机运行答案:
很奇怪的现象。
本以为是洛谷的bug,所以就搁置了。
HELLO 。Dev-C++运行答案:
HELLO 。洛谷IDE运行答案:
HELLO 。很正常对吧?
评测机运行答案:
Cannot Determine 。很奇怪的现象。
本以为是洛谷的bug,所以就搁置了。
然后呢?
前文的提到的大佬在中午放学时用班里的的大白板帮我调好了。
怎么调的?只加了一句代码:
作用:删除每条证言的最后一个字符。
前文的提到的大佬
怎么调的?只加了一句代码:
zynr[i].pop_back();作用:删除每条证言的最后一个字符。
接下来我们讲原理(继续感谢dalao的讲解):
洛谷的输入使用Windows操作系统,但评测使用Linux操作系统。
这就会产生一个问题:
Windows操作系统的换行符是
所以每条证言后都多了
洛谷的输入使用Windows操作系统,但评测使用Linux操作系统。
这就会产生一个问题:
Windows操作系统的换行符是
\r\n,但Linux操作系统的换行符是 \n。在Windows系统上传数据使用 getline 读入会将 \r 一并读入,Windows系统会省去,但Linux会保留。所以每条证言后都多了
\r ,之后比对自然出错。加上就AC了。
总结:都怪洛谷。NOI系列比赛是不会出现这种情况的,因为全程都是用Linux进行的。再说还有数据检查
请各位对此有兴趣的大佬进行讨论。
回复
共 3 条回复,欢迎继续交流。
正在加载回复...