【牛客】B 处女座的比赛资格(拓扑排序求最短路)

链接:https://ac.nowcoder.com/acm/contest/329/B
来源:牛客网

处女座想出去比赛,但是又不知道学校能不能给到足够的经费。然而处女座是大众粉丝,有着很好的人缘,于是他找了一个在学校管经费的地方勤工俭学偷来了一份报销标准。

由于处女座是万人迷,所以他在中间途径的每一条线路上都会发生一些故事,也许是粉丝给他发了一个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元
备注:
思路:这道题用普通的spfa会被卡,由于题目说了是有向无环图,所以可以用拓扑排序求最短路(我也是第一次学这种操作,就当见识一下)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
typedef long long ll;
struct cxk{
	int y;
	ll len;
	int next;
}a[maxn];
queue<int>q;
int n,m,T,tot,head[maxn],u[maxn],v[maxn],ru[maxn];
ll ans,c[maxn],num1[maxn],num2[maxn],d[maxn];
void init()
{
	tot=0;
	memset(head,-1,sizeof(head));
	memset(ru,0,sizeof(ru));
	memset(d,0x3f,sizeof(d));
	while(!q.empty()) q.pop();
}
void add(int x,int y,ll w)
{
	a[tot].y=y;a[tot].len=w;a[tot].next=head[x];head[x]=tot++;ru[y]++;
}
ll slove()
{
	d[1]=0;
	for(int i=1;i<=n;++i) if(ru[i]==0) q.push(i);
	while(!q.empty())
	{
		int t=q.front();
		q.pop();
		for(int i=head[t];i!=-1;i=a[i].next)
		{
			int to=a[i].y;
			if(d[to]>d[t]+a[i].len) d[to]=d[t]+a[i].len;
			ru[to]--;
			if(ru[to]==0) q.push(to);
		}
	}
	return d[n];
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;++i) scanf("%d%d%lld%lld%lld",&u[i],&v[i],&c[i],&num1[i],&num2[i]);
		init();
		for(int i=1;i<=m;++i) add(u[i],v[i],c[i]-num2[i]);
		ans=max(0LL,slove());
		init();
		for(int i=1;i<=m;++i) add(u[i],v[i],c[i]-num1[i]);
		ans-=max(0LL,slove());
		if(ans>0) cout<<"cnznb!!!"<<endl,cout<<ans<<endl;
		else if(ans<0) cout<<"rip!!!"<<endl,cout<<-ans<<endl;
		else cout<<"oof!!!"<<endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值