2020浙江大学计算机与软件学院保研上机题(代码简明)

本文通过三个编程题目详细介绍了深度优先搜索、并查集和优先级队列(最大最小堆)在解决实际问题中的应用。第一题涉及多项式的标准形式,通过递归实现深度优先搜索;第二题利用三指针法求解三元组的最小距离;第三题借助并查集解决部分学校排名问题;最后一题借助优先级队列优化购物清单。这些算法在信息技术领域有着广泛的应用。

小结:这套题比2019年浙大保研上机质量高太多了。考到的知识点有深度优先搜索、并查集、优先级队列(最大最小堆)。第二题是个很有意思的题,我使用了三指针法做,应该是这道题最简单的解法而且时间复杂度是n。这套题的第二题和第四题都在卡时间复杂度,基本上暴力解法和最优解法每题会差10分左右。每个题代码都比较清晰简短所以只给一点小提示,相信能做到这套卷的都应该看得明白。

7-1

Standard Form of Polynomial

(20分)

The standard form of a polynomial of degree n is P(x)=a​n​​x​n​​+a​n−1​​x​n−1​​+⋯+a​1​​x+a​0​​. Given that a​n​​=1 and all the n roots { r​1​​, ..., r​n​​ } of P(x) are integers. Then P(x) can be written as (x−r​1​​)(x−r​2​​)⋯(x−r​n​​). Your job is to write P(x) in its standard form with all roots given.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive n (≤10) which is the degree of P(x). Then n integer roots are given in the next line, separated by spaces.

Output Specification:

For each case, output the coefficients a​i​​ (i=n−1,⋯,0) in a line. All the numbers must be separated by one space, and there must be no extra space at the beginning or the end of the line. It is guaranteed that all the calculation will be within the range of int.

Sample Input:

3
-1 4 -1

Sample Output:

-2 -7 -4

提示:深度优先搜索。 

#include<cstdio>
#include<vector>
using namespace std;
const int maxn = 20;
int A[maxn],n;
bool vis[maxn]={false};
vector<int> v;
int cnt=0;
void dfs(int s,int limit)
{
	v.push_back(s);
	vis[s]=true;
	if(v.size()==limit){
		int tmp=1;
		for(int i=0; i<v.size(); i++){
			tmp*=A[v[i]];
		}
		cnt+=tmp;
		v.pop_back();
		vis[s]=false;
		return;
	}
	for(int i=s+1; i<n; i++){
		if(vis[i]==false){
			dfs(i,limit);
		}
	}
	vis[s]=false;
	v.pop_back();
}
int main()
{
	scanf("%d",&n);
	for(int i=0; i<n; i++){
		scanf("%d",&A[i]);
		A[i]=-A[i];
	}
	for(int limit=1; limit<=n; limit++){
		cnt=0;
		for(int i=0; i<n; i++){
			if(vis[i]==false){
				dfs(i,limit);
			}
		}
		printf("%d",cnt);
		if(limit!=n) printf(" ");
		else printf("\n");
	}
	return 0;
}

 

7-2

Distance of Triples

(25分)

The distance of triples (三元组) (a,b,c) is defined as D(a,b,c)=∣a−b∣+∣b−c∣+∣c−a∣. Now given three non-empty integer sets S​1​​, S​2​​ and S​3​​, you are supposed to find the minimum distance of all the possible triples (a,b,c) where a∈S​1​​, b∈S​2​​ and c∈S​3​​.

Input Specification:

Each input file contains one test case. For each case, the first line gives three positive integers N​1​​, N​2​​ and N​3​​ (all no more than 10​4​​), which are the sizes of S​1​​, S​2​​ and S​3​​, respectively. Then the members of the three sets are given in the following three lines, respectively. All the numbers are integers in the range [−10​4​​,10​4​​], and they are distinct within each set. The numbers in a line are separated by spaces.

Output Specification:

For each case, print in a line MinD(a, b, c) = d, where (a, b, c) are the triples that has the minimum distance, and d is the corresponding distance. If the solution is not unique, output the largest triples.

Sample Input:

4 4 6
0 9 -1 11
10 -25 11 -10
9 2 41 17 12 30

Sample Output:

MinD(11, 11, 12) = 2

Hint:

Notice that there are two solutions. The other one is MinD(9, 10, 9) = 2. Since (11, 11, 12) is larger, this one must be printed out.

提示:三指针,每次移动指向最小值的指针,直到三个指针都到终点。

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int inf = 1000000000;
vector<int> v1,v2,v3;
int n1,n2,n3;
int getMin(int p1, int p2, int p3)
{
	int Min=inf,index=-1;
	if(p1!=n1-1){
		if(v1[p1]<Min){
			Min = v1[p1];
			index = 1;
		}
	}
	if(p2!=n2-1){
		if(v2[p2]<Min){
			Min = v2[p2];
			index = 2;
		}
	}
	if(p3!=n3-1){
		if(v3[p3]<Min){
			Min = v3[p3];
			index = 3;
		}
	}
	return index;
}
int main()
{
	scanf("%d%d%d",&n1,&n2,&n3);
	v1.resize(n1);
	v2.resize(n2);
	v3.resize(n3);
	for(int i=0; i<n1; i++){
		scanf("%d",&v1[i]);
	}
	for(int i=0; i<n2; i++){
		scanf("%d",&v2[i]);
	}
	for(int i=0; i<n3; i++){
		scanf("%d",&v3[i]);
	}
	sort(v1.begin(),v1.end());
	sort(v2.begin(),v2.end());
	sort(v3.begin(),v3.end());
	int p1,p2,p3;
	p1=p2=p3=0;
	int index;
	int MinD=inf,mini,minj,mink,nowD; 
	while(true){
		nowD=abs(v1[p1]-v2[p2])+abs(v2[p2]-v3[p3])+abs(v1[p1]-v3[p3]);
		if(nowD<=MinD){
			MinD = nowD;
			mini = p1;
			minj = p2;
			mink = p3;
		}
		index = getMin(p1,p2,p3);
		if(index==1) p1++;
		else if(index==2) p2++;
		else if(index==3)p3++;
		else break;
	}
	printf("MinD(%d, %d, %d) = %d\n",v1[mini],v2[minj],v3[mink],MinD);
	return 0;
}

 

7-3

Partial School Ranking

(25分)

In a Group Programming Contest, each university is supposed to send n students who must compete independently. The universities are ranked according to the total score of their students. Your job is to generate the ranklist.

It sounds like a simple problem, but what makes it complicated is that we have lost all the teams' information! What we have is a list of only some of the students' scores, and some photos taken from the contest sites which shows several students with the same university badge. You just have to recover the ranklist as much as you can.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤1000). Then N lines follow, each gives the infomation of a student in the format:

ID k teammate​1​​⋯teammate​k​​ Score

where ID is a unique 4-digit identification number for a student; k (0≤k≤5) is the number of teammates of this student in a photo; teammate​i​​'s are the ID's of his/her teammate; and Score is this stdent's score which is in the range [0, 400].

It is guaranteed that each ID with a Score is given only once.

Output Specification:

For each case, first print in a line the number of universities (all the students that are related directly or indirectly as teammates are considered in the same university). Then output the partial school ranking in the format:

ID S Score​total​​

where ID is the smallest student ID in the university; S is the total number of its students; and Score​total​​ is the total score that can be recovered for that university. The universities must be given in descending order of their Score​total​​, or in ascending order of S if there is a tie, or in ascending order of ID if there is still a tie.

Sample Input:

11
7456 3 7457 7458 7459 157
6666 3 5551 5552 7777 100
1234 3 5678 9012 0002 80
8888 0 340
2468 3 0001 0004 2222 110
7777 1 6666 57
3721 1 2333 30
9012 3 1236 1235 1234 10
1235 2 5678 9012 50
2222 4 1236 2468 6661 6662 16
2333 4 3721 6661 6662 6663 44

Sample Output:

4
8888 1 340
0001 15 340
5551 4 157
7456 4 157

提示:并查集。 

#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 10000;
struct node{
	int score;
	int father;
	int total;
	node(){
		score=0;
		father=-1;
		total=1;
	}
}S[maxn];
struct university{
	int head;
	int id;
	int num;
	int score;
	university(){
		id=100000;
		num=0;
		score=0;
	}
};
void Union(int root1, int root2)
{
	if(S[root1].total>S[root2].total){
		S[root2].father = root1;
		S[root1].total+=S[root2].total;
	}
	else{
		S[root1].father = root2;
		S[root2].total+=S[root1].total;
	}
}
int myFind(int x)
{
	if(S[x].father==-1) return x;
	else return S[x].father = myFind(S[x].father); 
}
bool cmp(university a,university b)
{
	if(a.score!=b.score) return a.score>b.score;
	else if(a.num!=b.num) return a.num<b.num;
	else return a.id<b.id;
}
int main()
{
	set<int> st;
	int n,id,k,score,tmate,root1,root2;
	scanf("%d",&n);
	for(int i=0; i<n; i++){
		scanf("%d%d",&id,&k);
		st.insert(id);
		for(int j=0; j<k; j++){
			scanf("%d",&tmate);
			st.insert(tmate);
			root1 = myFind(id);
			root2 = myFind(tmate);
			if(root1!=root2){
				Union(root1,root2);
			}
		}
		scanf("%d",&score);
		S[id].score = score;
	}
	map<int,university> mp;
	int root;
	for(auto it=st.begin(); it!=st.end(); it++){
		root = myFind(*it);
		if(mp.count(root)==0){
			mp[root].head=root;
		}
		if(mp[root].id>*it) mp[root].id=*it;
		mp[root].num++;
		mp[root].score+=S[*it].score;
	}
	printf("%d\n",mp.size());
	vector<university> ans;
	for(auto it=mp.begin();it!=mp.end(); it++){
		ans.push_back(it->second);
	}
	sort(ans.begin(),ans.end(),cmp);
	for(int i=0; i<ans.size(); i++){
		printf("%04d %d %d\n",ans[i].id,ans[i].num,ans[i].score);
	}
	return 0;
}

 

7-4

Shopping With Coupons

(30分)

coupon.JPG

There are N items on your shopping list, and you have N kinds of coupon that can save you some money on buying any of these items. At the mean time, you have D dollars in your pocket. How can you buy as many items as you can? Here you may use any coupon many times and buy any item many times, but only one coupon may be used to get a reduction of payment for one item once -- that is, for example, you may use coupon A1 to buy item B1, and then use coupon A2 to buy item B1. At the mean time, coupon A1 can be used to buy item B2. But you may not use coupon A1 to buy item B1 AGAIN.

For example, suppose there are 4 items with prices of $10, $12, $15 and $20; and 4 kinds of coupons with values of $6, $7, $8 and $9. If you have $30 in your pocket, the best way to buy is the following:

  • buy $10 item for 4 times, with each coupon once, and hence pay $10x4 - $6 - $7 - $8 - $9 = $10 in total;
  • buy $12 item for 3 times, with coupons of $7, $8 and $9, and hence pay $12x3 - $7 - $8 - $9 = $12 in total;
  • buy $15 item with $9 coupon, and hence pay $6;

Now you have $2 left, not enough to buy any more items. Therefore the maximum number of items you can buy is 8.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers: N (≤10​5​​), the number of items (and the coupons), and D (≤10​6​​), the amount of money you have.

Then N positive prices are given in the second line, and N positive coupon values are given in the third line. It is guaranteed that the highest value of coupons is less than the lowest price of items, and all the numbers are bounded above by 10​9​​. The numbers in a line are separated by spaces.

Output Specification:

Print in a line the maximum number of items you can buy, and the maximum amount of money left, separated by 1 space.

Sample Input:

4 30
12 20 15 10
9 6 8 7

Sample Output:

8 2

提示:利用优先级队列。 

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 100000;
int A[maxn],B[maxn],record[maxn];
bool cmp(int a, int b)
{
	return a>b;
}
struct node{
	int product;
	int coupon;
	friend bool operator < (node a, node b){
		return A[a.product]-B[a.coupon]>A[b.product]-B[b.coupon];
	}
};
int main()
{
	int n,d;
	scanf("%d%d",&n,&d);
	for(int i=0; i<n; i++){
		scanf("%d",&A[i]);
	}
	for(int i=0; i<n; i++){
		scanf("%d",&B[i]);
	}
	sort(A,A+n);
	sort(B,B+n,cmp);
	priority_queue<node> q;
	node tmp;
	for(int i=0; i<n; i++){
		tmp.product = i;
		tmp.coupon = 0;
		q.push(tmp);
	}
	int total=0,cnt=0;
	while(!q.empty()){
		tmp=q.top(); q.pop();
		cnt++;
		total+=(A[tmp.product]-B[tmp.coupon]);
		//printf("%d\n",(A[tmp.product]-B[tmp.coupon]));
		if(total>d){
			total-=(A[tmp.product]-B[tmp.coupon]);
			cnt--;
			break;
		}
		if(tmp.coupon<n-1){
			tmp.coupon++;
			q.push(tmp);
		}
	}
	printf("%d %d\n",cnt,d-total);
	return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值