The Preliminary Contest for ICPC Asia Nanjing 2019 H. Holy Grail(spfa或floyd,负环)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The Preliminary Contest for ICPC Asia Nanjing 2019 H. Holy Grail(spfa或floyd,负环)相关的知识,希望对你有一定的参考价值。
题意
n n n个点, m m m条有向边,然后给你六组起始点( s s s点和 t t t点)
你要在 s s s和 t t t之间建一个有向边,添加后不能存在负循环
要使得权值最小,问这六组边依次是多少?(先前增加的边在后续不会消失)
(可以添加负边,题目给的边权也有可能为负)
暴力一点,显然加的边权具有单调性,越小越容易成为负环
就直接二分边权,然后从 s s s跑 s p f a spfa spfa判断是否有负环即可
然后判负环也可以使用 f l o y d floyd floyd,就是判断一下 d i s i , i dis_{i,i} disi,i是否为负数
但是每次二分都跑一次显然超时,我们可以插点,只把 s , t s,t s,t作为中介点来跑 f l o y d floyd floyd
这样总体复杂度是 O ( n 3 + 6 ∗ 2 ∗ n 2 ∗ l o g ( i n f ) ) O(n^3+6*2*n^2*log(inf)) O(n3+6∗2∗n2∗log(inf))
[SPFA二分]
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 5e11;
const int maxn = 2e5+10;
int n,m;
struct edge
{
int to,nxt,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w)
{
d[++cnt] = ( edge ){v,head[u],w}, head[u] = cnt;
}
int dis[maxn],vis[maxn],num[maxn];
bool spfa(int s)
{
for(int i=0;i<=n;i++) dis[i] = inf, vis[i] = num[i] = 0;
queue<int>q; q.push( s ); dis[s] = 0; num[s] = 1;
while( !q.empty() )
{
int u = q.front(); q.pop();
vis[u] = 0;
for(int i=head[u];i;i=d[i].nxt )
{
int v = d[i].to;
if( dis[u]+d[i].w<dis[v] )
{
dis[v] = dis[u]+d[i].w;
if( !vis[v] )
{
vis[v] = 1; q.push( v );
if( ++num[v]==n ) return false;
}
}
}
}
return true;
}
signed main()
{
int T; cin >> T;
while( T-- )
{
cin >> n >> m;
for(int i=1;i<=m;i++)
{
int l,r,w; scanf("%lld%lld%lld",&l,&r,&w);
add(l,r,w);
}
for(int i=1;i<=6;i++)
{
int s,t; scanf("%lld%lld",&s,&t);
int l = -inf, r = inf, ans = 0;
add( s,t,0 );
while( r>=l )
{
int mid = l+r>>1;
d[cnt].w = mid;
if( spfa(s) ) r = mid-1, ans = mid;
else l = mid+1;
}
d[cnt].w = ans;
cout << ans << endl;
}
cnt = 1;
for(int i=0;i<=n;i++) vis[i] = num[i] = head[i] = 0;
}
}
[floyd二分]
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 5e11;
const int maxn = 2e5+10;
int n,m;
int dis[309][309],ti[309][309];;
bool floyd(int s,int t)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ti[i][j] = dis[i][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ti[i][j] = min( ti[i][j],ti[i][s]+ti[s][j] );
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ti[i][j] = min( ti[i][j],ti[i][t]+ti[t][j] );
for(int i=0;i<n;i++)
if( ti[i][i]<0 ) return false;
return true;
}
signed main()
{
int T; cin >> T;
while( T-- )
{
cin >> n >> m;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if( i==j ) dis[i][j] = 0;
else dis[i][j] = inf;
}
for(int i=1;i<=m;i++)
{
int l,r,w; scanf("%lld%lld%lld",&l,&r,&w);
dis[l][r] = w;
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
dis[i][j] = min( dis[i][j],dis[i][k]+dis[k][j] );
for(int i=1;i<=6;i++)
{
int s,t; scanf("%lld%lld",&s,&t);
int l = -inf, r = inf, ans = 0;
while( r>=l )
{
int mid = l+r>>1;
dis[s][t] = mid;
if( floyd(s,t) ) r = mid-1, ans = mid;
else l = mid+1;
}
dis[s][t] = ans; floyd(s,t);
for(int j=0;j<n;j++)
for(int q=0;q<n;q++)
dis[j][q] = ti[j][q];
cout << ans << endl;
}
}
}
简单的
然而根本不需要二分,只需要从 t t t往 s s s跑最短路,设边权为 k k k
这么新加入的边权设置为 − k -k −k即可.
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 5e11;
const int maxn = 2e5+10;
int n,m;
struct edge
{
int to,nxt,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w)
{
d[++cnt] = ( edge ){v,head[u],w}, head[u] = cnt;
}
int dis[maxn],vis[maxn];
bool spfa(int s)
{
for(int i=0;i<=n;i++) dis[i] = inf, vis[i] = 0;
queue<int>q; q.push( s ); dis[s] = 0;
while( !q.empty() )
{
int u = q.front(); q.pop();
vis[u] = 0;
for(int i=head[u];i;i=d[i].nxt )
{
int v = d[i].to;
if( dis[u]+d[i].w<dis[v] )
{
dis[v] = dis[u]+d[i].w;
if( !vis[v] ) vis[v] = 1,q.push( v );
}
}
}
return true;
}
signed main()
{
int T; cin >> T;
while( T-- )
{
cin >> n >> m;
for(int i=1;i<=m;i++)
{
int l,r,w; scanf("%lld%lld%lld",&l,&r,&w);
add(l,r,w);
}
for(int i=1;i<=6;i++)
{
int s,t; scanf("%lld%lld",&s,&t);
spfa(t);
add( s,t,-dis[s] );
cout << d[cnt].w << endl;
}
cnt = 1;
for(int i=0;i<=n;i++) vis[i] = head[i] = 0;
}
}
以上是关于The Preliminary Contest for ICPC Asia Nanjing 2019 H. Holy Grail(spfa或floyd,负环)的主要内容,如果未能解决你的问题,请参考以下文章