给定 \(n\) 个形如 \(a-b≤c\) 的式子,求一组解或求两个变量间的最值
转化为图论问题跑最短/长路即可。
简化题意:给定一串约束条件,求所有元素的最小值。
稍微转换一下,就是使两个元素差值尽可能小。
例如 \(x_1+c≤x_2\) 如果用最短路去约束,则会取到最小值,所以应该用最长路去维护。
具体原因我也解释不来屮。
又因为题意对每个元素都有大于等于1的约束,所以从超级源点向每个元素的边边权要设为1。
这题就做完了,但是有些些小细节。
#include<bits/stdc++.h>
#define N 200005
#define int long long
using namespace std;
inline int read(){
int x=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w*x;
}
int n,k,cnt,ans;
int dis[N],head[N],tot[N];
bool vis[N];
struct node{int to,next,w;}edge[N<<1];
void add(int u,int v,int w){
edge[++cnt]=(node){v,head[u],w};
head[u]=cnt;
}
void spfa(){
stack<int> q;
q.push(0);
vis[0]=1;
while(!q.empty()){
int u=q.top();q.pop();vis[u]=0;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(dis[u]+edge[i].w>dis[v]){
dis[v]=dis[u]+edge[i].w;
if(!vis[v]){
vis[v]=1;tot[v]++;
if(tot[v]>=n) {puts("-1");exit(0);}
q.push(v);
}
}
}
}
}
signed main(){
n=read();k=read();
for(int i=1;i<=k;++i){
int x=read(),a=read(),b=read();
if(x==1) add(a,b,0),add(b,a,0);
else if(x==2) {
if(a==b){puts("-1");return 0;}
add(a,b,1);
}
else if(x==3) add(b,a,0);
else if(x==4) {
if(a==b){ puts("-1");return 0;}
add(b,a,1);
}
else add(a,b,0);
}
for(int i=1;i<=n;++i) add(0,i,1);
spfa();
for(int i=1;i<=n;++i)
ans+=dis[i];
printf("%lld",ans);
return 0;
}
最小值同理。
我真不知道啥时跑最长啥时跑最短屮。
考场上随机应变
——————water_tomato
upd. on 2022.7.15
好像又懂了,补充一下。
最大值
将约束条件转化为形如 \(dis_i\le dis_j+w\) 。
从 \(j\) 向 \(i\) 连一条边权为 \(w\) 的边,跑最短路。
为什么要跑最短路呢,因为跑最短路在这种情况下是跑到上界的,\(dis_i\) 就是把上界跑满的结果。
这样建图跑最长路就寄了,答案是错误的。
最小值
将约束条件转化为形如 \(dis_i\ge dis_j+w\) 。
从 \(j\) 向 \(i\) 连一条边权为 \(w\) 的边,跑最长路,也可以跑到上界。
我们令 \(dis_1=0\) ,则跑最长路跑出来的 \(dis_3=4\) ,刚好卡到上界。
跑最短路跑出来的 \(dis_3=2\) ,不满足 1 , 4 之间的关系。
上面的最大值同理。
参考资料
https://blog.csdn.net/thexue/article/details/123587112
标签:ch,int,短路,笔记,约束,vis,edge,差分,dis From: https://www.cnblogs.com/lxgswrz/p/18613589