社区讨论

有趣的现象+警钟

灌水区参与者 3已保存回复 3

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
3 条
当前快照
1 份
快照标识符
@m261szvc
此快照首次捕获于
2024/10/12 19:03
去年
此快照最后确认于
2025/11/04 17:22
4 个月前
查看原帖

本条水帖感谢 @xiaoke2021 这位dalao的倾力相助,膜拜orz。

事情是这样的:
几个月前我在写关于字符串练习的时候,遇上了这样一道有趣的题:P1039 [NOIP2003 提高组] 侦探推理(可以先去读题)。
读完题目,很明显这是枚举。于是写出如下代码(也就用了几星期):
CPP
#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
调了很久,仍旧发现不了问题。甚至我下载了一组数据,发现了一个很奇特的情况:
数据如下:
CPP
2 2 4
HELLO
GUILTY
HELLO: What is your name?
GUILTY: I am GUILTY.
GUILTY: Are you guilty?
HELLO: I am not guilty.
正确答案: HELLO
Dev-C++运行答案:HELLO
洛谷IDE运行答案:HELLO
很正常对吧?
评测机运行答案: Cannot Determine
很奇怪的现象。
本以为是洛谷的bug,所以就搁置了。
然后呢?
前文的提到的大佬在中午放学时用班里的的大白板帮我调好了。
怎么调的?只加了一句代码:
zynr[i].pop_back();
作用:删除每条证言的最后一个字符。
接下来我们讲原理(继续感谢dalao的讲解):
洛谷的输入使用Windows操作系统,但评测使用Linux操作系统。
这就会产生一个问题:
Windows操作系统的换行符是 \r\n,但Linux操作系统的换行符是 \n。在Windows系统上传数据使用 getline 读入会将 \r 一并读入,Windows系统会省去,但Linux会保留。
所以每条证言后都多了 \r ,之后比对自然出错。
加上就AC了。
总结:都怪洛谷。NOI系列比赛是不会出现这种情况的,因为全程都是用Linux进行的。再说还有数据检查
请各位对此有兴趣的大佬进行讨论。

回复

3 条回复,欢迎继续交流。

正在加载回复...