链接: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元
备注:
T≤10
2≤N≤
1≤M≤2⋅
1≤u,v≤N
0≤c≤
−≤cnz,jffzr≤
题解:负权值边的存在使得 Dijkstra 算法不适用,特殊 DAG 的性质使得 SPFA 算法无法在规定的时间限内求解出答案。 考虑到 DAG 的特殊性,按照原图节点的拓扑顺序依次递推距离即可求解。
按照节点拓扑顺序计算d即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f;
const int maxn=2e5+5;
int T,n,m;
struct node{
int x,y;
ll c;
node(){}
node(int a,int b,ll d):x(a),y(b),c(d){}
}pos;
vector<node> v1[maxn];
ll dis1[maxn],c[maxn],cnz[maxn],jffzr[maxn];
int x[maxn],y[maxn],d[maxn];
void dj1()
{
queue<int> q;
memset(dis1,INF,sizeof(dis1));
dis1[1]=0;
for(int i=1;i<=n;i++)
if(d[i]==0)
q.push(i);
while(!q.empty())
{
int xx=q.front();q.pop();
for(int i=0;i<v1[xx].size();i++)
{
int y=v1[xx][i].y; ll dd=v1[xx][i].c;
if(dis1[y]>=dis1[xx]+dd)
dis1[y]=dis1[xx]+dd;
d[y]--;
if(d[y]==0)q.push(y);
}
}
}
int main()
{
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++) v1[i].clear();
for(int i=0;i<m;i++)scanf("%d%d%lld%lld%lld",&x[i],&y[i],&c[i],&cnz[i],&jffzr[i]);
for(int i=0;i<m;i++)
{
v1[x[i]].push_back(node(x[i],y[i],c[i]-cnz[i]));
d[y[i]]++;
}
dj1();
memset(d,0,sizeof(d));
ll tt1=max(0ll,dis1[n]);
for(int i=1;i<=n;i++) v1[i].clear();
for(int i=0;i<m;i++)
{
v1[x[i]].push_back(node(x[i],y[i],c[i]-jffzr[i]));
d[y[i]]++;
}
dj1();
ll tt2=max(0ll,dis1[n]);
ll ttt=tt2-tt1;
if(ttt>0)
{
printf("cnznb!!!\n");
printf("%lld\n",ttt);
}
else if(ttt==0)
{
printf("oof!!!\n");
}
else {
printf("rip!!!\n");
printf("%lld\n",abs(ttt));
}
}
return 0;
}