PAT 2020年秋 7-4 Professional Ability Test (30 分) AC代码(拓扑排序以及DFS)

该篇博客介绍了如何使用拓扑排序判断一个考试计划的合理性,并通过深度优先搜索找到获取证书的最短路径。文章通过具体样例展示了算法的实现过程,包括检查计划是否自相矛盾以及在不一致时如何找出可以直接参加的考试。同时,博客还提供了AC代码作为解决方案。
摘要由CSDN通过智能技术生成

7-4 Professional Ability Test (30 分)

Professional Ability Test (PAT) consists of several series of subject tests. Each test is divided into several levels. Level A is a prerequisite (前置要求) of Level B if one must pass Level A with a score no less than S in order to be qualified to take Level B. At the mean time, one who passes Level A with a score no less than S will receive a voucher(代金券)of D yuans (Chinese dollar) for taking Level B.

At the moment, this PAT is only in design and hence people would make up different plans. A plan is NOT consistent if there exists some test T so that T is a prerequisite of itself. Your job is to test each plan and tell if it is a consistent one, and at the mean time, find the easiest way (with minimum total S) to obtain the certificate of any subject test. If the easiest way is not unique, find the one that one can win the maximum total value of vouchers.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers N (≤1000) and M, being the total numbers of tests and prerequisite relations, respectively. Then M lines follow, each describes a prerequisite relation in the following format:

T1 T2 S D

where T1 and T2 are the indices (from 0 to N−1) of the two distinct tests; S is the minimum score (in the range (0, 100]) required to pass T1 in order to be qualified to take T2; and D is the value of the voucher (in the range (0, 500]) one can receive if one passes T1 with a score no less than S and plan to take T2. It is guaranteed that at most one pair of S and D are defined for a prerequisite relation.

Then another positive integer K (≤N) is given, followed by K queries of tests. All the numbers in a line are separated by spaces.

Output Specification:

Print in the first line Okay. if the whole plan is consistent, or Impossible. if not.

If the plan is consistent, for each query of test T, print in a line the easiest way to obtain the certificate of this test, in the format:

T0->T1->...->T

However, if T is the first level of some subject test (with no prerequisite), print You may take test T directly. instead.

If the plan is impossible, for each query of test T, check if one can take it directly or not. If the answer is yes, print in a line You may take test T directly.; or print Error. instead.

Sample Input 1:

8 15
0 1 50 50
1 2 20 20
3 4 90 90
3 7 90 80
4 5 20 20
7 5 10 10
5 6 10 10
0 4 80 60
3 1 50 45
1 4 30 20
1 5 50 20
2 4 10 10
7 2 10 30
2 5 30 20
2 6 40 60
8
0 1 2 3 4 5 6 7

结尾无空行

Sample Output 1:

Okay.
You may take test 0 directly.
0->1
0->1->2
You may take test 3 directly.
0->1->2->4
0->1->2->4->5
0->1->2->6
3->7

结尾无空行

Sample Input 2:

4 5
0 1 1 10
1 2 2 10
3 0 4 10
3 2 5 10
2 0 3 10
2
3 1

结尾无空行

Sample Output 2:

Impossible.
You may take test 3 directly.
Error.

结尾无空行

先用拓扑排序判断consistent,再用DFS来找最短路径(这道题DFS比dijkstra方便,或者可以采取增加一个结点连接所有可能起点,再用一次dijkstra的思路),注意剪枝

AC代码:

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int N,M,K;
int start[1000]={0};
int G[1000][1000];
int r[1000][1000]={0};
int inf=1000000000;
vector<int> plan;
vector<int> pre[1000];
struct node{
	int in=0;
	vector<int> next;
}Node[1000];
int maxr=0,mins=inf;
vector<int> path,temppath;
bool is_cyclic(){
	queue<int> q;
	for(int i=0; i<N; i++){
		if(Node[i].in==0) q.push(i);
	} 
	int u,cnt=0;
	while(!q.empty()){
		u = q.front(); q.pop(); cnt++;
		for(int v=0; v<Node[u].next.size(); v++){
			int index=Node[u].next[v];
			Node[index].in--;
			if(Node[index].in==0) q.push(index);
		}
	}
	if(cnt==N) return true;
	else return false;
}
void dfs(int s,int sums,int sumr){
	if(sums>mins) return;
	temppath.push_back(s);
	if(start[s]==1){
		if(sums<mins){
			path=temppath;
			mins=sums;
			maxr=sumr;
		}else if(sums==mins&&sumr>maxr){
			path=temppath;
			maxr=sumr;
		}
		temppath.pop_back();
		return;
	}
	for(auto it:pre[s]){
		dfs(it,sums+G[it][s],sumr+r[it][s]);
	}
	temppath.pop_back();
}
int main(){
	cin>>N>>M;
	fill(G[0],G[0]+1000*1000,inf);
	for(int i=0;i<M;i++){
		int a,b;
		scanf("%d %d",&a,&b);
		Node[b].in++;
		Node[a].next.push_back(b);
		pre[b].push_back(a);
		scanf("%d %d",&G[a][b],&r[a][b]);
	}
	for(int i=0;i<N;i++){
		if(Node[i].in==0) start[i]=1;
	}
	cin>>K;
	plan.resize(K);
	bool flag=is_cyclic();
	for(int i=0;i<K;i++){
		scanf("%d",&plan[i]);
	}
	if(flag){
		printf("Okay.\n");
	}else{
		printf("Impossible.\n");
		for(int i=0;i<K;i++){
			if(start[plan[i]]==1){
				printf("You may take test %d directly.\n",plan[i]);
			}else{
				printf("Error.\n");
			}
		}
		return 0;
	}
	for(int i=0;i<K;i++){
		int index=plan[i];
		if(start[index]==1){
			printf("You may take test %d directly.\n",index);
			continue;
		}
		maxr=0,mins=inf;
		path.clear();
		temppath.clear();
		dfs(index,0,0);
		for(int i=path.size()-1;i>=0;i--){
			if(i==path.size()-1){
				printf("%d",path[i]);
			}else{
				printf("->%d",path[i]);
			}
		}
		printf("\n");
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值