传送门
由于有一个判负环的步骤,所以费用流里面求最短路可以直接用Johnson算法。
然后我Johnson敲挂了T了五次。。。
题解:
考虑实际上就是给出了 2 m 2m 2m个限制:
L i ≤ p u i − q v i ≤ R i L_i\leq p_{u_i}-q_{v_i}\leq R_i Li≤pui−qvi≤Ri
有没有解可以利用差分约束。
拆开看一下是一个线性规划:
l i m i t s : p u i − q v i ≤ R i q v i − p u i ≤ L i m a x i m i m a l : ∑ u o u t u p u − i n u q u \begin{aligned} limits:&&&&&&p_{u_i}-q_{v_i}\leq R_i\\ &&&&&&q_{v_i}-p_{u_i}\leq L_i\\ maximimal:&&&&&&\sum_{u}out_up_u-in_uq_u \end{aligned} limits:maximimal:pui−qvi≤Riqvi−pui≤Liu∑outupu−inuqu
其中 o u t u out_u outu是 u u u的出度, i n u in_u inu是 u u u的入度。
感觉像是一个网络流的形式,但是不好建图,对偶一下:
l i m i t s : ∀ u , ∑ ( u , v ) ∈ E x u , v − y u , v ≥ o u t u ∀ v , ∑ ( u , v ) ∈ E y u , v − x u , v ≥ − i n v m i n i m i m a l : ∑ i R i x i + L i y i \begin{aligned} limits:&&&&&&\forall u,\sum_{(u,v)\in E}x_{u,v}-y_{u,v}\geq out_u\\ &&&&&&\forall v,\sum_{(u,v)\in E}y_{u,v}-x_{u,v}\geq -in_v\\ minimimal:&&&&&& \sum_{i}R_ix_i+L_iy_i \end{aligned} limits:minimimal:∀u,(u,v)∈E∑xu,v−yu,v≥outu∀v,(u,v)∈E∑yu,v−xu,v≥−invi∑Rixi+Liyi
这里网上另一篇题解是写错了的:https://blog.csdn.net/geotcbrl/article/details/74779985
把所有限制加起来得到 0 ≥ 0 0\geq 0 0≥0,则所有等号必须取到,考虑利用流量平衡来实现这一点。
然后可以建图跑网络流了,每个点拆成两个,一个入点一个出点,原点向入点连容量为该点入度的边,出点向汇点连容量为出度的边。
然后对于每个变量 x , y x,y x,y,我们把它当做一条边,按照符号决定方向,负号为出正号为入,容量为INF,费用为最小化式子里面带的权,然后跑最小费用最大流。
如果没有满流,或者出现负环则无解,出现负环意味着原差分约束无解。
否则有解,我们看一下流了哪些边,表示对应 p , q p,q p,q的约束取了等号,加到差分约束里面跑就行了。
可以把差分约束源点向外连的点的权值设置大一点避免出现负数。
或者也可以跑完差分约束之后减去全局最小值。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;bool f=false;
while(!isdigit(c=gc()))f=c=='-';num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
using pii=std::pair<int,int>;
#define fi first
#define se second
cs int N=250,INF=0x3f3f3f3f;
namespace NetWork{
int n,S,T;
struct edge{int to,rev,cap,w;};
typedef std::vector<edge>::iterator iter;
std::vector<edge> G[N];iter cur[N];
int h[N],dis[N];bool vis[N];
inline void init(int _n){
S=_n-1,T=_n,n=_n;memset(h+1,0,sizeof(int)*n);
for(int re i=1;i<=n;++i)G[i].clear();
}
inline void adde(int u,int v,int cap,int cost){
G[u].push_back((edge){v,G[v].size(),cap,cost});
G[v].push_back((edge){u,G[u].size()-1,0,-cost});
}
inline bool check(){//negative circle and connectivity
static short cnt[N];
memset(vis+1,0,sizeof(bool)*n);
memset(dis+1,0x3f,sizeof(int)*n);
std::deque<int> q(1,T);dis[T]=0,cnt[T]=0;
while(!q.empty()){
int u=q.front();q.pop_front();vis[u]=false;
for(auto e:G[u])
if(G[e.to][e.rev].cap&&dis[e.to]>dis[u]-e.w){
dis[e.to]=dis[u]-e.w;
if((cnt[e.to]=cnt[u]+1)>n)return true;
if(!vis[e.to]){
if(!q.empty()&&dis[e.to]<dis[q.front()])q.push_front(e.to);
else q.push_back(e.to);
vis[e.to]=true;
}
}
}
if(dis[S]>=INF)return true;
for(int re i=1;i<=n;++i)if(dis[i]<INF)h[i]+=dis[i];
return false;
}
inline bool Dij(){
memset(dis+1,0x3f,sizeof(int)*n);
memset(vis+1,0,sizeof(bool)*n);
std::priority_queue<pii,std::vector<pii>,std::greater<pii> > q;
q.push(pii(dis[T]=0,T));
while(!q.empty()){
int u=q.top().se;q.pop();
if(vis[u])continue;vis[u]=true;
for(auto e:G[u])if(G[e.to][e.rev].cap){
int w=-e.w+h[u]-h[e.to];
if(dis[e.to]>dis[u]+w)q.push(pii(dis[e.to]=dis[u]+w,e.to));
}
}
return dis[S]<INF;
}
int dfs(int u,int flow){
if(u==T)return flow;
vis[u]=true;int ans=0;
for(iter e=G[u].begin();e!=G[u].end();++e)
if(e->cap&&!vis[e->to]&&
dis[e->to]+e->w-h[u]+h[e->to]==dis[u]){
int delta=dfs(e->to,std::min(flow-ans,e->cap));
if(!delta){vis[e->to]=true;continue;}
e->cap-=delta;
G[e->to][e->rev].cap+=delta;
if((ans+=delta)==flow)break;
}
vis[u]=false;return ans;
}
inline ll Flow(int expected){
if(check())return -1;
int tot_flow=0;ll tot_cost=0;
while(Dij()){
memset(vis+1,0,sizeof(bool)*n);
int delta=dfs(S,INF);
for(int re i=1;i<=n;++i)if(dis[i]<INF)h[i]+=dis[i];
tot_flow+=delta,tot_cost+=(ll)delta*h[S];
}
return tot_flow==expected?tot_cost:-1;
}
}
namespace Diff{
int n;
struct edge{int to,w;};
std::vector<edge> G[N];
int dis[N];bool vis[N];
inline void init(int _n){
n=_n;for(int re i=1;i<=n;++i)G[i].clear();
}
inline void adde(int u,int v,int w){
G[u].push_back((edge){v,w});
}
inline void SPFA(int S){
memset(dis+1,0x3f,sizeof(int)*n);
memset(vis+1,0,sizeof(bool)*n);
std::deque<int> q;q.push_back(S);dis[S]=0;
while(!q.empty()){
int u=q.front();q.pop_front();vis[u]=false;
for(auto e:G[u])if(dis[e.to]>dis[u]+e.w){
dis[e.to]=dis[u]+e.w;
if(!vis[e.to]){
if(!q.empty()&&dis[e.to]<dis[q.front()])q.push_front(e.to);
else q.push_back(e.to);
vis[e.to]=true;
}
}
}
}
}
int n,m;
int in[N],out[N];
inline void solve(){
n=gi(),m=gi();ll ans=0;
NetWork::init(2*n+2);Diff::init(2*n+1);
memset(in+1,0,sizeof(int)*n);
memset(out+1,0,sizeof(int)*n);
for(int re i=1;i<=m;++i){
int u=gi(),v=gi(),w=gi();
++out[u],++in[v];ans+=w;
int s=gi(),t=gi();
NetWork::adde(v+n,u,INF,t-w);
NetWork::adde(u,v+n,INF,w-s);
Diff::adde(v+n,u,t-w);
Diff::adde(u,v+n,w-s);
}
for(int re i=1;i<=n;++i){
NetWork::adde(i,NetWork::T,out[i],0);
NetWork::adde(NetWork::S,i+n,in[i],0);
}
ll res=NetWork::Flow(m);
if(res==-1){cout<<"Unlike\n";return ;}
cout<<(ans+res)<<"\n";
for(int re u=1;u<=2*n;++u)
for(auto e:NetWork::G[u]){
if(NetWork::G[e.to][e.rev].cap)
Diff::adde(e.to,u,-e.w);
}
for(int re i=1;i<=2*n;++i){
Diff::adde(2*n+1,i,1e6);
Diff::adde(i,2*n+1,0);
}Diff::SPFA(2*n+1);
for(int re i=1;i<=n;++i)cout<<Diff::dis[i]<<" ";cout<<"\n";
for(int re i=1;i<=n;++i)cout<<Diff::dis[i+n]<<" ";cout<<"\n";
}
signed main(){
#ifdef zxyoi
freopen("chefbook.in","r",stdin);
#endif
int T=gi();while(T--)solve();
return 0;
}