处女座的比赛资格(拓扑排序+最短路)
题目:
处女座想出去比赛,但是又不知道学校能不能给到足够的经费。然而处女座是大众粉丝,有着很好的人缘,于是他找了一个在学校管经费的地方勤工俭学偷来了一份报销标准。
由于处女座是万人迷,所以他在中间途径的每一条线路上都会发生一些故事,也许是粉丝给他发了一个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(i); 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 }