题解:UVA1148 (差分约束)
题解:UVA1148 (差分约束)
一道差分约束的好题。
不难发现,操作的顺序对答案没有影响。如果存在一条边 \((x,y)\) ,不妨设 \(S_x\) 为对 \(x\) 操作的 \(d\) 值之和,设 \(S_y\) 为对 \(y\) 操作的距离之和。
这个题的问法是经典的二分答案,我们假设现在二分到 \(mid\) ,如果 \(mid\) 合法,我们有:
\[S_y-S_x\ge w(x,y)-t
\]
不难发现,这是一个差分约束。这个题就做完了。
注意,用 SPFA 判负环会 TLE ,所以我们最好用 DFS ,虽然最坏复杂度一样,但一般情况下不会到达最坏复杂度。
另一个是二分边界的问题,注意左界必须是 \(0\) 而不能是一个负数,因为有可能这张图全部都是 \(0\) 边。
代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define int ll
#define uint unsigned int
#define ull unsigned long long
#define N 550000
#define M 300000
using namespace std;
const int INF=0x3f3f3f3f;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
struct edge{
int to,next,w;
inline void intt(int to_,int ne_,int w_){
to=to_;next=ne_;w=w_;
}
};
edge li[M];
int head[N],tail;
inline void add(int from,int to,int w){
li[++tail].intt(to,head[from],w);
head[from]=tail;
}
int n,m,d[N],s;
bool vis[N],app[N];
inline bool dfs(int k){
vis[k]=1;
for(int x=head[k];x;x=li[x].next){
int to=li[x].to,w=li[x].w;
if(d[to]>d[k]+w){
d[to]=d[k]+w;
if(vis[to]||dfs(to)) return 1;
}
}
vis[k]=0;
return 0;
}
inline bool check(int mid){
for(int i=1;i<=m;i++) li[i].w-=mid;
memset(vis,0,sizeof(vis));memset(d,INF,sizeof(d));d[s]=0;
bool pd=dfs(s);
for(int i=1;i<=m;i++) li[i].w+=mid;
return 1^pd;
}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
bool op=1;
while(scanf("%lld%lld",&n,&m)!=EOF){
// if(n==-1&&m==-1) break;
tail=0;memset(head,0,sizeof(head));
memset(li,0,sizeof(li));memset(app,0,sizeof(app));
for(int i=1;i<=m;i++){
int from,to,w;read(from);read(to);read(w);
add(from,to,w);
app[from]=app[to]=1;
}
for(int i=1;;i++) if(!app[i]){s=i;break;}
for(int i=1;i<=n;i++) add(s,i,0);
int l=0,r=1e9;
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
if(l==0) printf("No Solution\n");
else if(l==1e9) printf("Infinite\n");
else printf("%lld\n",l);
}
return 0;
}