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.数组
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:less
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.ide
Then another positive integer K (≤N) is given, followed by K queries of tests. All the numbers in a line are separated by spaces.测试
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:ui
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.this
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.spa
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
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
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
Impossible. You may take test 3 directly. Error.
有N个考试,M个考试的相互之间的关系,如今咱们把这N场考试和M条关系称之为一个考试计划,请问当前的计划是不是一个consistent的计划,并给出了K场考试的查询,若是是一个consistent的计划,要求给出经过当前考试最为快速的方法,若是有多种,选择得到代金券最多的那种。若是不是一个consistent的计划,那么判断当前考试T是否能够直接考取,若是是就输出You may take test T directly.
不然输出Error.
。code
首先得理解题意,plan是指每个测试用例,而不是每个查询,consistent的判断方法就是判断当前图中是否有环,因为是有向图,可使用拓扑排序来进行判断.
对于含有环的图,须要知道当前查询的结点是否入度为0,所以使用zeroDegree集合保存每个入度为0的结点(inDegree在拓扑排序的时候会发生变化),对于入度为0的点直接输出You may take test T directly.
就好,不然输出Error.
对于不含有环的图,咱们须要找到一条到查询结点的最短路径,这里使用迪杰斯特拉算法解决,可是没有给定起点,仔细读题发现起点必定是那些读入为0的结点,由于只有入度为0的点才能没有任何前置条件进行考试,可是若是对每个入度为0的起点进行遍历得到最短路径的话,最后两个测试点会运行超时,因此这里采用一个小技巧,咱们认为设立一个顶点,其入度为0,而且将该顶点指向当前图中的全部入度为0的顶点,而且边权设置为0,这样整个图中入度为0的顶点就刚好只有一个了,每个顶点的最短路径的获取只须要执行一遍迪杰斯特拉算法便可。
这里简要说明下为何该方法可行,由于从该点出发,必定先经原图中入度为0的起点,也就是真正的起点,那么该图中全部结点的最短路径必定是比较了全部原图中起点以后所得到的,而且边权为0,不会影响最短距离。
而后对于每个查询的考生科目,判断是否在原图中是入度为0的结点,若是是,输出You may take test T directly.
,不然使用DFS遍历该结点的路径(在获取最短距离的时候,每个结点的前驱保存在了pre数组中,所以能够直接获取)
#include<cstdio> #include<queue> #include<string> #include<cstring> #include<unordered_set> using namespace std; int N,M;//顶点数和边数 vector<int> Adj[1005];//邻接表 int score[1005][1005];//score[a][b]表明a测试点得到的最低得分能够有资格考b考试 int voucher[1005][1005];//voucher[a][b]表明a测试点得到score[a][b]及以上分数能够获得考b的代金券 int inDegree[1005];// 每个顶点的入度 bool inQueue[1005];// 标记已经入队的节点 unordered_set<int> zeroDegree;// 图中全部入度为0的顶点,这里指原图中入度为0的顶点 // 拓扑排序判断是否有环存在 bool topologicalOrder(){ queue<int> q; int num = 0; // 入队全部入度为0的顶点 for(int i=0;i<N;++i){ if(inDegree[i]==0){ inQueue[i] = true; q.push(i); } } while (!q.empty()){ int t = q.front(); q.pop(); ++num;//统计入队的结点个数 // 将t的临界点的入度所有减一 for(int vertex:Adj[t]){ --inDegree[vertex]; // 将入度为0且没有入队的节点入队 if(inDegree[vertex]==0){ q.push(vertex); } } } return num==N;// true表示没有环 } int dis[1005];// 每个节点到起点的最短距离(分数) int money[1005];// 每个节点到起点得到到最大代金券 bool visited[1005];// 标记每个节点是否访问 int pre[1005];// 每个节点的前驱节点 void Dijsktra(int start){ fill(dis,dis+1005,0x3ffffff); dis[start] = 0; money[start] = 0; for(int i=0;i<N+1;++i){// N+1个顶点 // 找出距离起点最短的未访问节点 int min_dis = 0x3fffff; int min_index = -1; for(int j=0;j<N+1;++j){ if(!visited[j]&&dis[j]<min_dis){ min_dis = dis[j]; min_index = j; } } if(min_index==-1) return; visited[min_index] = true; // 优化路径 for(int j=0;j<Adj[min_index].size();++j){ int v = Adj[min_index][j]; if(!visited[v]){ if(dis[v]>dis[min_index]+score[min_index][v]){ // 当前路径更短 pre[v] = min_index; dis[v] = dis[min_index]+score[min_index][v]; money[v] = money[min_index] + voucher[min_index][v]; } else if(dis[v]==dis[min_index]+score[min_index][v]&&money[v]<money[min_index]+voucher[min_index][v]){ // 须要考试的分数同样,可是得到的代金券更多 pre[v] = min_index; money[v] = money[min_index] + voucher[min_index][v]; } } } } } void DFS(int end){ if(pre[end]==N){ // 到达起点 printf("%d",end); return; } DFS(pre[end]); printf("->%d",end); } void consistent(int query[],int K){ Dijsktra(N);// 得到每个结点的最短距离和路径 for(int i=0;i<K;++i){ if(zeroDegree.find(query[i])!=zeroDegree.end()){ // 当前考试没有前置条件 printf("You may take test %d directly.",query[i]); }else{ DFS(query[i]); } if(i<K-1) printf("\n"); } } void notConsistent(int query[],int K){ for(int i=0;i<K;++i){ if(zeroDegree.find(query[i])!=zeroDegree.end()){ // 当前考试没有前置条件 printf("You may take test %d directly.",query[i]); }else{ printf("Error."); } if(i<K-1) printf("\n"); } } int main(){ scanf("%d %d",&N,&M); for (int i = 0; i < M; ++i) { int a,b; scanf("%d %d",&a,&b); scanf("%d %d",&score[a][b],&voucher[a][b]); ++inDegree[b]; Adj[a].push_back(b); } // 添加一个入度为0的顶点,顶点编号为N,与全部入度为0的顶点链接一条边,这样N就是惟一的入度为0的顶点了 for(int i=0;i<N;++i){ if(inDegree[i]==0){ Adj[N].push_back(i); zeroDegree.insert(i); } } int K; scanf("%d",&K); int query[K]; for(int i=0;i<K;++i){ scanf("%d",&query[i]); } bool isOk = topologicalOrder(); if(isOk){ printf("Okay.\n"); consistent(query,K); } else { printf("Impossible.\n"); notConsistent(query,K); } return 0; }