PAT 2018秋季考试甲级 1148-1151

1148 Werewolf - Simple Version(20 分)

Werewolf(狼人杀) is a game in which the players are partitioned into two parties: the werewolves and the human beings. Suppose that in a game,

  • player #1 said: "Player #2 is a werewolf.";
  • player #2 said: "Player #3 is a human.";
  • player #3 said: "Player #4 is a werewolf.";
  • player #4 said: "Player #5 is a human."; and
  • player #5 said: "Player #4 is a human.".

Given that there were 2 werewolves among them, at least one but not all the werewolves were lying, and there were exactly 2 liers. Can you point out the werewolves?

Now you are asked to solve a harder version of this problem: given that there were N players, with 2 werewolves among them, at least one but not all the werewolves were lying, and there were exactly 2 liers. You are supposed to point out the werewolves.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (5≤N≤100). Then N lines follow and the i-th line gives the statement of the i-th player (1≤i≤N), which is represented by the index of the player with a positive sign for a human and a negative sign for a werewolf.

Output Specification:

If a solution exists, print in a line in ascending order the indices of the two werewolves. The numbers must be separated by exactly one space with no extra spaces at the beginning or the end of the line. If there are more than one solution, you must output the smallest solution sequence -- that is, for two sequences A=a[1],...,a[M] and B=b[1],...,b[M], if there exists 0≤k<M such that a[i]=b[i] (i≤k) and a[k+1]<b[k+1], then A is said to be smaller than B. In case there is no solution, simply print No Solution.

Sample Input 1:

5
-2
+3
-4
+5
+4

Sample Output 1:

1 4

Sample Input 2:

6
+6
+3
+1
-5
-2
+4

Sample Output 2 (the solution is not unique):

1 5

Sample Input 3:

5
-2
-3
-4
-5
-1

Sample Output 3:

No Solution

题目大意:已知 N 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家,如果有解,在一行中按递增顺序输出 2 个狼人的编号;如果解不唯一,则输出最小序列解;若无解则输出 No Solution~

分析:每个人说的数字保存在v数组中,i从1~n、j从i+1~n遍历,分别假设i和j是狼人,a数组表示该人是狼人还是好人,等于1表示是好人,等于-1表示是狼人。k从1~n分别判断k所说的话是真是假,k说的话和真实情况不同(即v[k] * a[abs(v[k])] < 0)则表示k在说谎,则将k放在lie数组中;遍历完成后判断lie数组,如果说谎人数等于2并且这两个说谎的人一个是好人一个是狼人(即a[lie[0]] + a[lie[1]] == 0)表示满足题意,此时输出i和j并return,否则最后的时候输出No Solution~

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(){
	int n;
	cin>>n;
	
	vector<int> v(n+1);
	for(int i=1;i<=n;i++)
		cin>>v[i];
	
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
		{
			vector<int> lie,a(n+1,1);
			a[i] = a[j] = -1;
			for(int k=1;k<=n;k++)
				if(v[k] * a[abs(v[k])] < 0)//判断谁说慌,说谎者说的话和真实情况正相反,不说谎者一样 
					lie.push_back(k);
			if(lie.size() == 2 && a[lie[0]] + a[lie[1]] == 0){//两人说慌并且一人是狼一人是好人 
				cout<<i<<" "<<j;//输出谁是狼人 
				return 0;
			}
		}
	
	cout<<"No Solution";
	
	
	return 0;
}

1149 Dangerous Goods Packaging(25 分)

When shipping goods with containers, we have to be careful not to pack some incompatible goods into the same container, or we might get ourselves in serious trouble. For example, oxidizing agent (氧化剂) must not be packed with flammable liquid (易燃液体), or it can cause explosion.

Now you are given a long list of incompatible goods, and several lists of goods to be shipped. You are supposed to tell if all the goods in a list can be packed into the same container.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers: N (≤10​4​​), the number of pairs of incompatible goods, and M (≤100), the number of lists of goods to be shipped.

Then two blocks follow. The first block contains N pairs of incompatible goods, each pair occupies a line; and the second one contains M lists of goods to be shipped, each list occupies a line in the following format:

K G[1] G[2] ... G[K]

where K (≤1,000) is the number of goods and G[i]'s are the IDs of the goods. To make it simple, each good is represented by a 5-digit ID number. All the numbers in a line are separated by spaces.

Output Specification:

For each shipping list, print in a line Yes if there are no incompatible goods in the list, or No if not.

Sample Input:

6 3
20001 20002
20003 20004
20005 20006
20003 20001
20005 20004
20004 20006
4 00001 20004 00002 20003
5 98823 20002 20003 20006 10010
3 12345 67890 23333

Sample Output:

No
Yes
Yes

题目大意:集装箱运输货物时,我们必须特别小心,不能把不相容的货物装在一只箱子里。比如氧化剂绝对不能跟易燃液体同箱,否则很容易造成爆炸。给定一张不相容物品的清单,需要你检查每一张集装箱货品清单,判断它们是否能装在同一只箱子里。对每箱货物清单,判断是否可以安全运输。如果没有不相容物品,则在一行中输出 Yes,否则输出 No~

解题分析:先将不能混一起的物品通过map与vector/set进行容合存储。接着使用temp来进行hash模拟,本次出现的物品全部为一。接着对每个物品,检查对应不能混在一起的是否有被标记为一。有则为No.否则为true. (查找过程一定要用hash,这样会简单很多!!!)

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
using namespace std;

int main(){
	int n,m;
	cin>>n>>m;
	
	int a,b;
	map<int,vector<int>> mp;
	for(int i=0;i<n;i++){
		cin>>a>>b;
		mp[a].push_back(b);
		mp[b].push_back(a);
	}
	
	int k,num;
	for(int i=0;i<m;i++){
		cin>>k;
		vector<int> v(k);
		int temp[100001] = {0};//数组初始化一定要为0,否则会发生错误!!! 
	
		for(int j=0;j<k;j++){
			cin>>num;
			v[j] = num;
			temp[num] = 1;
		}
		
		int flag = 0;
		for(int j=0;j<v.size();j++)
		{
			for(int k=0;k < mp[v[j]].size();k++)
			{
				if(temp[mp[v[j]][k]] == 1)
					flag = 1;
			}
		}
		if(flag == 1)
			cout<<"No"<<endl;
		else
			cout<<"Yes"<<endl;		
				
	}
	
		
	return 0;
}

 用set:

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
using namespace std;

int main(){
	int n,m;
	cin>>n>>m;
	
	int a,b;
	map<int,set<int>> mp;
	for(int i=0;i<n;i++){
		cin>>a>>b;
		mp[a].insert(b);
		mp[b].insert(a);
	}
	
	int k,num;
	for(int i=0;i<m;i++){
		cin>>k;
		vector<int> v(k);
		int temp[100001] = {0};//数组初始化一定要为0,否则会发生错误!!! 
	
		for(int j=0;j<k;j++){
			cin>>num;
			v[j] = num;
			temp[num] = 1;
		}
		
		int flag = 0;
		for(int j=0;j<v.size();j++)
		{
			set<int> s = mp[v[j]];
			for(auto it:s)
				if(temp[it] == 1)
					flag = 1;
			
		}
		if(flag == 1)
			cout<<"No"<<endl;
		else
			cout<<"Yes"<<endl;		
				
	}
		
	return 0;
}

7-3 Travelling Salesman Problem(25 分)

The "travelling salesman problem" asks the following question: "Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city and returns to the origin city?" It is an NP-hard problem in combinatorial optimization, important in operations research and theoretical computer science. (Quoted from "https://en.wikipedia.org/wiki/Travelling_salesman_problem".)

In this problem, you are supposed to find, from a given list of cycles, the one that is the closest to the solution of a travelling salesman problem.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N(2<N≤200), the number of cities, and M, the number of edges in an undirected graph. Then M lines follow, each describes an edge in the format City1 City2 Dist, where the cities are numbered from 1 to N and the distance Dist is positive and is no more than 100. The next line gives a positive integer K which is the number of paths, followed by K lines of paths, each in the format:

n C​1​​ C​2​​ ... C​n​​

where n is the number of cities in the list, and C​i​​'s are the cities on a path.

Output Specification:

For each path, print in a line Path X: TotalDist (Description) where X is the index (starting from 1) of that path, TotalDist its total distance (if this distance does not exist, output NAinstead), and Description is one of the following:

  • TS simple cycle if it is a simple cycle that visits every city;
  • TS cycle if it is a cycle that visits every city, but not a simple cycle;
  • Not a TS cycle if it is NOT a cycle that visits every city.

Finally print in a line Shortest Dist(X) = TotalDist where X is the index of the cycle that is the closest to the solution of a travelling salesman problem, and TotalDist is its total distance. It is guaranteed that such a solution is unique.

Sample Input:

6 10
6 2 1
3 4 1
1 5 1
2 5 1
3 1 8
4 1 6
1 6 1
6 3 1
1 2 1
4 5 1
7
7 5 1 4 3 6 2 5
7 6 1 3 4 5 2 6
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 2 5 4 3 1
7 6 3 2 5 4 1 6

Sample Output:

Path 1: 11 (TS simple cycle)
Path 2: 13 (TS simple cycle)
Path 3: 10 (Not a TS cycle)
Path 4: 8 (TS cycle)
Path 5: 3 (Not a TS cycle)
Path 6: 13 (Not a TS cycle)
Path 7: NA (Not a TS cycle)
Shortest Dist(4) = 8

题目大意:给出一条路径,判断这条路径是这个图的旅行商环路、简单旅行商环路还是非旅行商环路~

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
using namespace std;

const int N = 220;
const int inf = 999999;
int edge[N][N];
bool vst[N];

int main(){
	fill(edge[0],edge[0]+N*N,inf);
	fill(vst,vst+N,false);
	int n,m;
	cin>>n>>m;
	
	for(int i=0;i<m;i++){
		int a,b,c;
		cin>>a>>b>>c;
		edge[a][b] = edge[b][a] = c;
	}
	
	int k;
	cin>>k;
	vector<int> vec[k];
	for(int i=0;i<k;i++)
	{
		int num,a;
		cin>>num;
		for(int j=0;j<num;j++){
			cin>>a;
			vec[i].push_back(a);
		}	
	}
	
	int sum = 0,min = inf,minid = -1;
	for(int i=0;i<k;i++){
		sum = 0;
		vector<int> temp(n+1,0);
		int a,b;
		for(int j=0;j<vec[i].size() - 1;j++){
			a = vec[i][j];
			b = vec[i][j+1];
			temp[a] += 1;//temp标记访问过的点 
			sum += edge[a][b];
		}
		temp[b] += 1;
		
		int flag = -1;//flag来标记是哪一种情况 
		int mval = -1;
		
		for(int i=1;i<=n;i++){
			mval = max(temp[i],mval);
		}
		if(mval == 2) flag = 1;
		else if(mval >= 3) flag = 2;
		else flag = 0;//不是 
	
		for(int i=1;i<=n;i++)
			if(temp[i] == 0)
				flag = 0;
			
		if(vec[i][0] != vec[i][vec[i].size()-1])
			flag = 0;
		
		if(min > sum && flag){
			minid = i+1;
			min = sum;
		}
		
		printf("Path %d: ",i+1);
		if(sum < 99999){
			cout<<sum;
			if(flag == 1)
				cout<<" (TS simple cycle)"<<endl;
			else if(flag == 2)
				cout<<" (TS cycle)"<<endl;
			else if(flag == 0)
				cout<<" (Not a TS cycle)"<<endl;
		}
		else
			cout<<"NA"<<" (Not a TS cycle)"<<endl;
	}
	printf("Shortest Dist(%d) = %d",minid,min);
	
	return 0;
	
}

7-4 LCA in a Binary Tree(30 分)

The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

Given any two nodes in a binary tree, you are supposed to find their LCA.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.

Output Specification:

For each given pair of U and V, print in a line LCA of U and V is A. if the LCA is found and A is the key. But if A is one of U and V, print X is an ancestor of Y. where X is A and Y is the other node. If U or V is not found in the binary tree, print in a line ERROR: U is not found. or ERROR: V is not found. or ERROR: U and V are not found..

Sample Input:

6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99

Sample Output:

LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

题目大意:给出中序序列和先序序列,再给出两个点,求这两个点的最近公共祖先~

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

vector<int> in,pre;
vector<int> temppath;

struct node{
	int data;
	struct node *left;
	struct node *right;
};

//通过前序、中序序列构建出BT 
node *createBT(node *&root,int pleft,int pright,int ileft,int iright){
	if(pleft > pright || ileft > iright)
		return nullptr;
	int data = pre[pleft];
	
	root = new node();
	root->data = data;
	
	int index = ileft;
	while(index <= iright && in[index] != data) index++;
	int len = index - ileft;
	root->left = createBT(root->left,pleft+1,pleft+len,ileft,ileft+len-1);
	root->right = createBT(root->right,pleft+len+1,pright,ileft+len+1,iright);
	
	return root;//注意将根结点返回 
}

//先序遍历找出路径,与dfs寻找路径思想一致 
void preorder(node *root,int data,int &flag,vector<int> &path){
	if(root == nullptr || flag == 1)
		return;
	
	temppath.push_back(root->data);
	if(root->data == data)
	{
		path = temppath;
		flag = 1;
		return ;
	}
	
	preorder(root->left,data,flag,path);
	preorder(root->right,data,flag,path);
	
	temppath.pop_back();//结束遍历node时,将node节点弹出path栈
} 

//查找结点是否存在,若存在则flag标记为1 
void search(node *root,int data,int &flag){
	if(root == nullptr)
		return;
	if(root->data == data)
		flag = 1;
	search(root->left,data,flag);
	search(root->right,data,flag);
}

int main(){
	int m,n;
	cin>>m>>n;
	in.resize(n);
	pre.resize(n);
	
	for(int i=0;i<n;i++){
		cin>>in[i];
	}	
	for(int i=0;i<n;i++)
		cin>>pre[i];
		
	node *bt = nullptr;
	createBT(bt,0,n-1,0,n-1);
	
	int a,b;
	for(int i=0;i<m;i++){
		cin>>a>>b;
		int f1 = 0,f2 = 0;
		search(bt,a,f1);
		search(bt,b,f2);
		if(f1 == 0 && f2 == 0)
			printf("ERROR: %d and %d are not found.\n",a,b);
		else if(f1 == 0)
			printf("ERROR: %d is not found.\n",a);
		else if(f2 == 0)
			printf("ERROR: %d is not found.\n",b);
		else{
			int flag = 0;
			//path与flag一定要用引用 
			temppath.clear();//因为循环使用temppath,所以要记得清空!!! 
			vector<int> path_1;
			preorder(bt,a,flag,path_1);//找到a点路径 
			
			temppath.clear();
			flag = 0;
			vector<int> path_2;
			preorder(bt,b,flag,path_2);
			
			int len,res;
			len = min(path_1.size(),path_2.size());
			for(int i=0;i<len;i++)
				if(path_1[i] == path_2[i])//通过两条路径找到最近公共祖先 
					res = path_1[i];
			
			if(res != a && res != b)
				printf("LCA of %d and %d is %d.\n",a,b,res);
			else if(res == a)
				printf("%d is an ancestor of %d.\n",res,b);
			else if(res == b)
				printf("%d is an ancestor of %d.\n",res,a);	
				
		}
	}
	
	return 0;	
}

猜你喜欢

转载自blog.csdn.net/qq_29762941/article/details/82559320