题面
分析
这题面tmd太有迷惑性了,比赛的时候完全没有想到费用流。
考虑到k只有200,尝试费用流(思想类似可撤销贪心? )
一次一次增广,每次spfa能跑过去。 每走过一条边,给他的边更新一下贡献。
Demo
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=1e3+10,M=8*2e4+10;
int add[M];
int to[M],f[M],cost[M],final[N],tot,nex[M],from[M];
int n,m,k,s;
int S,T;
int pre[N],dis[N],ans;
void _link(int x,int y,int l,int c,int a) {
to[++tot]=y, nex[tot]=final[x], final[x]=tot;
add[tot]=a, cost[tot]=c, f[tot]=l;
from[tot]=x;
}
void link(int x,int y,int l,int c,int add)
{_link(x,y,l,c+add,add), _link(y,x,0,-c,add);}
int Q[N*100],head,tail,vis[N];
void spfa() {
memset(dis,127,sizeof dis);
head=tail=0;
dis[S]=0, Q[++tail]=S;
while (head<tail) {
int x=Q[++head]; vis[x]=0;
for (int i=final[x]; i; i=nex[i]) {
int y=to[i];
if (f[i] && dis[x]+cost[i]<dis[y]) {
dis[y]=dis[x]+cost[i];
pre[y]=i;
if (!vis[y]) {
Q[++tail]=y;
vis[y]=1;
}
}
}
}
}
void go() {
for (int x=pre[T]; x; x=pre[from[x]]) {
ans+=cost[x];
f[x]-=1, f[x^1]+=1;
cost[x]+=add[x];
cost[x^1]-=add[x];
}
}
int main() {
freopen("game.in","r",stdin);
// freopen("game.out","w",stdout);
scanf("%d %d %d %d",&n,&m,&k,&s);
tot=1, S=n+1, T=S+1;
link(S,1,k,0,0);
for (int i=1; i<=s; i++) {
int u; scanf("%d",&u);
link(u,T,k,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);
link(x,y,c,b,a);
}
int cnt=0;
while (spfa(), dis[T]!=dis[0]) go(), ++cnt;
if (cnt<k) printf("-1\n"); else printf("%d",ans);
}