应该是20分题里面容易出问题的题目了。
思路一(可行但是复杂,不推荐,推荐下面的思路二):
(可以帮助这个思路写但是测试点3不过的同学,因为现实中解这种问题可能更多先想到这思路)
拿到题目我的第一思路是:分别假设两个人撒谎,反转撒谎人的话,然后根据他们的话去确定身份,再在不违背已知身份的条件下,假设说谎人身份一狼一好,然后统计符合狼数条件的情况。
!!!要注意的问题:根据所有人的话,再加上你不违背话的假设,无法确定每个人的身份,有的人是好人,有的人是狼人,还有部分是无法确定的身份,这个时候会出现两种可能满足的情况:
1、遍历后发现,有两只狼,满足所有条件,将狼号存入ans
2、遍历后发现,有一只狼,且有无法确定身份之人,可以满足条件,将狼号和第一个不确定身份的人的号码(因为输出条件中只要号码小的,只需要存该情况下,最小的可能狼)存入ans(存的时候用一下,max和min保证一下大小顺序)
AC代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N;
struct node{
int a,b;
};
vector<int> v;
vector<node> ans;
bool cmp(const node x1,const node x2){
if(x1.a==x2.a){
return x1.b<x2.b;
}else{
return x1.a<x2.a;
}
}
int main(){
cin>>N;
v.resize(N+1);
for(int i=1;i<=N;i++){
scanf("%d",&v[i]);
}
for(int i=1;i<N;i++){
for(int j=i+1;j<=N;j++){ //假设i和j说谎
int tag[N+1]={0};
bool flag1=true;
vector<int> test=v;
test[i]*=-1; //反转话语
test[j]*=-1;
for(int m=1;m<=N;m++){
if(test[m]>0){
if(tag[test[m]]==-1){ //排除矛盾
flag1=false;
break;
}
tag[test[m]]=1;
}else{
if(tag[abs(test[m])]==1){ //排除矛盾
flag1=false;
break;
}
tag[abs(test[m])]=-1;
}
}
if(flag1){
vector<int> temp,temp0;
int ct=0;
if(tag[i]!=-1&&tag[j]!=1){ //假设i好,j狼
tag[i]=1;
tag[j]=-1;
for(int m=1;m<=N;m++){
if(tag[m]==-1){ //存狼
ct++;
temp.push_back(m);
}
if(tag[m]==0){ //存身份不确定的人
temp0.push_back(m);
}
}
if(ct==1&&temp0.size()!=0){ //一狼且有不确定的人
ans.push_back(node{min(temp[0],temp0[0]),max(temp[0],temp0[0])});
}
if(ct==2){ //恰好两狼
ans.push_back(node{temp[0],temp[1]});
}
}
if(tag[i]!=1&&tag[j]!=-1){ //假设i狼,j好
tag[i]=-1;
tag[j]=1;
ct=0;
temp.clear();
temp0.clear();
for(int m=1;m<=N;m++){
if(tag[m]==-1){
ct++;
temp.push_back(m);
}
if(tag[m]==0){
temp0.push_back(m);
}
}
if(ct==1&&temp0.size()!=0){ //一狼且有不确定的人
ans.push_back(node{min(temp[0],temp0[0]),max(temp[0],temp0[0])});
}
if(ct==2){ //恰好两狼
ans.push_back(node{temp[0],temp[1]});
}
}
}
}
}
sort(ans.begin(),ans.end(),cmp);
if(ans.size()==0){
printf("No Solution\n");
}else{
printf("%d %d\n",ans[0].a,ans[0].b);
}
return 0;
}
思路二(推荐,参考了柳神的思路,秒,膜)
直接假设两狼,其他是好,然判断其余条件:
1、是否恰好两人说谎
2、说谎人一好一狼
满足则将此情况统计
AC代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N;
vector<int> v;
struct node{
int a,b;
};
bool cmp(const node x1,const node x2){
if(x1.a==x2.a){
return x1.b<x2.b;
}else{
return x1.a<x2.a;
}
}
int main(){
cin>>N;
v.resize(N+1);
vector<node> ans;
for(int i=1;i<=N;i++){
scanf("%d",&v[i]);
}
for(int i=1;i<N;i++){
for(int j=i+1;j<=N;j++){
vector<int> tag(N+1,1);
vector<int> liar;
tag[i]=-1;
tag[j]=-1;
for(int m=1;m<=N;m++){
if(v[m]*tag[abs(v[m])]<0){
liar.push_back(m);
}
}
if(liar.size()==2&&(tag[liar[0]]*tag[liar[1]]==-1)){
ans.push_back(node{i,j});
}
}
}
sort(ans.begin(),ans.end(),cmp);
if(ans.size()==0){
printf("No Solution\n");
}else{
printf("%d %d\n",ans[0].a,ans[0].b);
}
return 0;
}