1. 程式人生 > 實用技巧 >處女座的比賽資格(拓撲排序+最短路)

處女座的比賽資格(拓撲排序+最短路)

題目:

處女座想出去比賽,但是又不知道學校能不能給到足夠的經費。然而處女座是大眾粉絲,有著很好的人緣,於是他找了一個在學校管經費的地方勤工儉學偷來了一份報銷標準。

由於處女座是萬人迷,所以他在中間途徑的每一條線路上都會發生一些故事,也許是粉絲給他發了一個200元的微信紅包,也許是和他的迷妹一起吃飯花了500元。

而經費負責人也實地考察了每一條路線,在每一條路上,也許是天降紅包雨,也許是地生劫匪。每一條路上都有屬於自己的奇遇。

而經費負責人也只能根據他的故事決定這一路批下來多少經費。他會找出從寧波到比賽地的最小花費,並以此作為標準給處女座打比賽。而處女座也會選擇對他來說最小花費的路線,來節省使用。

處女座想知道,最終的經費是否夠用,如果夠還會剩下來多少錢。如果不夠,他自己要自費掏出多少錢。(當然處女座和經費管理人都具有旅途中無限信貸額度,所有收入支出會在旅行結束後一起結算。)

輸入:

輸入檔案第一行包含一個整數T,表示處女座要參加的比賽場數。

對於每一場比賽,第一行包含兩個整數\(N,M\),分別表示旅行中的站點數(其中寧波的編號為\(1\),比賽地的編號為\(N\))和線路數。

接下來\(M\)行,每一行包含5個整數\(u,v,c,cnz,jffzr\),分別表示從\(u\)到\(v\)有一條單向的線路,這條線路的票價為\(c\)。處女座搭乘這條線路的時候,會得到\(cnz\)元(如果為負即為失去\(cnz\)元);經費負責人搭乘這條線路的時候,會得到\(jffzr\)元(如果為負即為失去\(jffzr\)元)。

行程保證不會形成環,並保證一定能從寧波到達比賽地。

輸出:

對於每一場比賽,如果經費負責人給出的經費綽綽有餘,則先在一行輸出"cnznb!!!",並在下一行輸出他可以餘下的經費;如果處女座的經費不夠用,則先在一行輸出"rip!!!",並在下一行輸出他需要自費的金額;如果經費負責人給出的經費正好夠處女座用,則輸出一行"oof!!!"。(所有輸出不含引號)

示例1:

輸入:

1
3 3
1 2 300 600 -600
2 3 100 -300 1
1 3 200 0 0

輸出:

cnznb!!!
100

說明:處女座先走第一條路再走第二條路到達,總花費100元,經費負責人走第三條路,花費200元,處女座經費剩餘100元

資料範圍:

\(1\leq T \leq 10\)

\(2\leq N\leq 10^{5}\)

\(1\leq M\leq 2\cdot 10^{5}\)

\(1\leq u,v\leq N\)

\(0\leq c\leq 10^{9}\)

\(−10^{9}\leq cnz,jffzr\leq 10^{9}\)

題解:由於存在負權邊,所以沒法用 \(dij\)來求最短路,\(SPFA對DAG圖來說不穩定\),但是既然是\(DAG\)圖,就可以按拓撲序來求解最小花費,然後判斷兩種花費情況就好了

AC_Code:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef long double ld;
 5 #define endl '\n'
 6 const int inf=0x3f3f3f3f;
 7 const int maxn=1e5+10;
 8 const int maxm=5e5+10;
 9 const int mod=1e9+7;
10 
11 struct edge{
12     int to,nxt;
13     ll w;
14 }e[maxm];
15 int head[maxn],cnt,in[maxn];
16 ll dis[maxn];
17 int n,m;
18 
19 struct node{
20     int u,v;
21     ll w,c,j;
22 }a[maxn];
23 
24 void init(){
25     cnt=0;
26     memset(head,-1,sizeof(head));
27     memset(dis,inf,sizeof(dis));
28     memset(in,0,sizeof(in));
29 }
30 
31 void addedge(int u,int v,ll w){
32     e[cnt].to=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt++;
33 }
34 
35 ll Topo(){
36     queue<int>q;
37     for(int i=1;i<=n;i++){
38         if( in[i]==0 ) q.push(1);
39     }
40     dis[1]=0;
41     while( !q.empty()){
42         int u=q.front(); q.pop();
43         for(int i=head[u];~i;i=e[i].nxt){
44             int v=e[i].to;
45             if( dis[v]>dis[u]+e[i].w ){
46                 dis[v]=dis[u]+e[i].w;
47             }
48             in[v]--;
49             if( in[v]==0 ){
50                 q.push(v);
51             }
52         }
53     }
54     return dis[n]>=0?dis[n]:0;
55 }
56 
57 int main()
58 {
59     int t; scanf("%d",&t);
60     while( t-- ){
61         init();
62         scanf("%d%d",&n,&m);
63         for(int i=0;i<m;i++){
64             scanf("%d%d%lld%lld%lld",&a[i].u,&a[i].v,&a[i].w,&a[i].c,&a[i].j);
65             addedge(a[i].u,a[i].v,a[i].w-a[i].c);
66             in[a[i].v]++;
67         }
68         ll ans1=Topo();
69 
70         init();
71         for(int i=0;i<m;i++){
72             addedge(a[i].u,a[i].v,a[i].w-a[i].j);
73             in[a[i].u]++;
74         }
75         ll ans2=Topo();
76 
77         if( ans1==ans2 ){
78             printf("oof!!!\n");
79         }
80         else if( ans1<ans2 ){
81             printf("cnznb!!!\n");
82             printf("%lld\n",ans2-ans1);
83         }
84         else{
85             printf("rip!!!\n");
86             printf("%lld\n",ans1-ans2);
87         }
88     }
89     return 0;
90 }