P4878 [USACO05DEC]Layout G 差分约束
题目大意
- 和人类一样,奶牛们在打饭的时候喜欢和朋友站得很近。
- 约翰的编号为 1 到 n 的 n(2<=n<=1000) 只奶牛正打算排队打饭。现在请你来安排她们,让她们在数轴上排好队。奶牛的弹性很好,同一个坐标可以站无限只奶牛,排队的顺序必须和她们编号的顺序一致。
- 有 M 对奶牛互相爱慕,她们之间的距离不能超过一定的值,有 K 对奶牛互相敌视,她们的距离不能小于一定的值。那么,首尾奶牛的最大距离是多少呢?
输入格式
- 第一行输入 n,M,K,(0<M,K<=5000)。
- 接下来 M 行每行三个整数x,y,z,表示编号为 x 和 y 的两头奶牛之间的距离最大不超过 z。
- 再接下来 K 行每行三个整数 a,b,c,表示编号为 a 和 b 的两头奶牛之间的距离最少为c。
输出格式
- 如果没有合理方案,输出 −1,如果首尾两头牛的距离可以无限大,输出 −2,否则输出一个整数表示首尾奶牛的最大距离。
样例输入
4 2 1
1 3 10
2 4 20
2 3 3
样例输出
27
算法分析
- 不会吧不会吧不会真的有人看不出来这是差分约束吧
- 然后就是一个差分约束的板子题了
- 建边跑最短路(求最大值)
- 建超级源点
算法展示
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10,maxm = 2e4+10;
const int Inf = 0x3f3f3f3f;
int n;
int head[maxn],cnt;
int num[maxn],dis[maxn],vis[maxn];
struct node{
int next,to,dis;
}a[maxm];
void add(int x,int y,int z){
a[++cnt].to = y;
a[cnt].next = head[x];
a[cnt].dis = z;
head[x] = cnt;
}
queue<int> q;
int spfa(int u){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
q.push(u);vis[u] = 1;
dis[u] = 0;
while(!q.empty()){
int u = q.front();q.pop();vis[u] = 0;
for(int i = head[u];i;i = a[i].next){
int v = a[i].to;
if(dis[v] > dis[u] + a[i].dis){
dis[v] = dis[u] + a[i].dis;
if(!vis[v]){
vis[v] = 1;q.push(v);
num[v]++;
if(num[v] > n)return -1;//判负环
}
}
}
}
if(dis[n] == Inf)return -2;//如果无限大
return dis[n];
}
int main(){
int m,k;scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= m;++i){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
if(x > y)swap(x,y);
add(x,y,z);
}
for(int i = 1;i <= k;++i){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
if(x > y)swap(x,y);
add(y,x,-z);//建边
}
for(int i = 1;i < n;++i)add(i+1,i,0);//建边
for(int i = 1;i <= n;++i)add(0,i,0);//超级源点
if(spfa(0) == -1){printf("-1\n");return 0;}//超级源点为起点跑spfa 防止有的负环无法到达的情况
printf("%d\n",spfa(1));
return 0;
}
谢谢观看>:<
如初见 与初见