题目描述
$NYG$在上网时,被广告吸引,进入了一个叫“一刀$999$级”的游戏。
这个游戏总共有$n$个剧情点和$m$道关卡,一道关卡从一个剧情点通向另一个剧情点。
其中一号剧情点被称为新手村。没有关卡通向新手村,剧情不会形成循环。(其实就是一个以$1$结点为根的有向无环图)。
其中有$s$个剧情点被称为“完结点”,代表可以从这个剧情点结束游戏,因为$NYG$很高贵,所以他觉得要至少玩过$k$次游戏才能算通关(即从新手村走到完结点$k$次)。$NYG$作为一名现充,当然要爽快的用软妹币通关这个游戏(不然怎么符合他高贵的身份呢?)每个关卡的怪物都有一个值,代表$NYG$要通过这个关卡所需要的软妹币数目,当然怪物会随着死亡刷新越来越强,第$x$次打败怪物需要$A_ix+B_i$的软妹币,而且怪物也是有自尊心的,当怪物第$C_i$次被$NYG$用钱砸死时他就会躲起来,导致$NYG$不能通过这个关卡。
$NYG$想知道他通关至少需要多少软妹币,以便统一从银行取(当然不是为了省钱啊),他钦定由你来解决。
输入格式
第一行包括四个数$n,m,k,s$表示有$n$个剧情点,$m$个关卡,要玩$k$次游戏,$s$个完结点接下来一行包含$s$个数,代表$s$个完结点的编号。
接下来$m$行,每行五个正整数$x_i,y_i,A_i,B_i,C_i$,代表第$i$号关卡从$x_i$号剧情点连向$y_i$号剧情点,$A_i,B_i,C_i$意义如题目描述。
输出格式
如果不能通关输出$-1$,否则输出一个整数,代表至少需要的软妹币值。
样例
样例输入:
6 8 2 2
4 5
1 2 4 0 2
1 3 5 0 2
3 4 1 5 1
2 5 1 0 1
4 6 4 2 2
5 6 0 4 2
1 5 5 9 2
2 6 4 5 2
样例输出:
16
数据范围与提示
样例解释:
第一次从$1−>2−>5$,费用为$5$。
第二次从$1−>3−>4$,费用为$11$。
数据范围:
对于$30\%$的数据,$A_i=0$。
对于另外$20\%$的数据,游戏为一条链。
对于$100\%$的数据,$1\leqslant n\leqslant 1,000,1\leqslant m\leqslant 20,000,1\leqslant k\leqslant 200,A_i,B_i\geqslant 0,1\leqslant C_i\leqslant k$。
保证答案在$int$范围内。
题解
注意到$k$只有200,但是又有谁能想到是费用流呢?
实际上,我的思路和题解稍有偏差。
建边的时候记录上边的$A,B$,每走一次就让花费增加,退流的时候再剪掉就好了,缺点就是每次只能流一个,不然有可能会错过最优答案。
时间复杂度:$\Theta(m\times k+n\times k^2)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec
{
int nxt;
int to;
int w;
int f;
int a;
}e[100001];
int head[5001],cnt=1;
int n,m,k,s;
int S,T;
int que[100001],pre[50001],dis[50001];
bool vis[50001];
int ans;
void add(int x,int y,int w,int f,int a)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
e[cnt].f=f;
e[cnt].a=a;
head[x]=cnt;
}
bool bfs()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[S]=0;
vis[S]=1;
int he=1,ta=1;
que[ta]=S;
while(he<=ta)
{
for(int i=head[que[he]];i;i=e[i].nxt)
if(e[i].w&&dis[que[he]]+e[i].f<dis[e[i].to])
{
dis[e[i].to]=dis[que[he]]+e[i].f;
pre[e[i].to]=i;
if(!vis[e[i].to])
{
vis[e[i].to]=1;
que[++ta]=e[i].to;
}
}
vis[que[he]]=0;
he++;
}
return dis[T]!=1061109567;
}
void update()
{
int flag=T;
while(flag!=S)
{
int x=pre[flag];
ans+=e[x].f;
e[x].w--;
e[x^1].w++;
e[x].f+=e[x].a;
e[x^1].f-=e[x].a;
flag=e[x^1].to;
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&s);
S=n+1,T=n+2;
add(S,1,k,0,0);
add(1,S,0,0,0);
for(int i=1;i<=s;i++)
{
int x;
scanf("%d",&x);
add(x,T,k,0,0);
add(T,x,0,0,0);
}
for(int i=1;i<=m;i++)
{
int x,y,a,b,c;
scanf("%d%d%d%d%d",&x,&y,&a,&b,&c);
add(x,y,c,b+a,a);
add(y,x,0,-b,a);
}
cnt=0;
while(bfs())
{
update();
cnt++;
}
if(cnt<k)puts("-1");
else printf("%d",ans);
return 0;
}
rp++