Layout POJ - 3169 (差分约束 + spfa)

题目链接

题目:当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。FJ有N(2<=N<=1000)头奶牛,编号从1到N,沿一条直线站着等候喂食。奶牛排在队伍中的顺序和它们的编号是相同的。因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。即使说,如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。

一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数L。另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数D。给出ML条关于两头奶牛间有好感的描述,再给出MD条关于两头奶牛间存有反感的描述。(1<=ML,MD<=10000,1<=L,D<=1000000)

你的工作是:如果不存在满足要求的方案,输出-1;如果1号奶牛和N号

奶牛间的距离可以任意大,输出-2;否则,计算出在满足所有要求的情况下,1号奶牛和N号奶牛间可能的最大距离。

 

!!! 简述一下差分约束:用于求解如, a - b <= c,这样有多个不等式,最后求两个参数的最大差值。

如: a - b <= c, b - d <= c 这个不等式组, 求 a,d之前的最大差值,即 2c ...

!!! 还有一点需要注意的,此类题目 往往可能会有环,记得用SPFA判环

形如 a - b <= c 这样的不等式,可转化为一条a 到 b,权值为 c 的有向边。(不是这样的不等式,转化一下即可),有 a[1] - a[x] 的最大差值就是 1 到 x 的最短路

 

AC代码:

#include<cstdio>
#include<cstring>
#include<queue>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

const int maxn = 1e3 + 10;
const int inf = 0x3f3f3f3f;
int head[maxn];
int cnt = 0;
struct xx{
    int v,nex,w;
    xx(){}
    xx(int v,int nex,int w):
        v(v),nex(nex),w(w){}
}edge[maxn * 100];
int dis[maxn];
int coun[maxn];
int vis[maxn];
int N,ML,MD;

void init(){
    for(int i = 0;i < maxn;i ++){
        head[i] = -1;
        dis[i] = inf;
        coun[i] = vis[i] = 0;
    }
    cnt = 0;
}

bool spfa(int x){
    dis[x] = 0;
    queue<int>Q;
    vis[x] = 1;
    Q.push(x);
    while(!Q.empty()){
        int now = Q.front();
        Q.pop(); vis[now] = 0;
        for(int i = head[now]; ~i;i = edge[i].nex){
            int v = edge[i].v;
            int w = edge[i].w;
            if(dis[v] > dis[now] + w){
                dis[v] = dis[now] + w;
                if(!vis[v]){
                    ++ coun[v];
                    vis[v] = 1;
                    if(coun[v] >= N)
                        return 1;
                    Q.push(v);
                }
            }
        }
    }
    return 0;
}

int main()
{
    while(~scanf("%d%d%d",&N,&ML,&MD)){
        init();
        for(int i = 1;i <= ML;i ++){
            int a,b,c; scanf("%d%d%d",&a,&b,&c);
            edge[cnt] = xx(b,head[a],c);
            head[a] = cnt ++;
        }
        for(int i = 1;i <= MD;i ++){
            int a,b,c; scanf("%d%d%d",&a,&b,&c);
            edge[cnt] = xx(a,head[b],-c);
            head[b] = cnt ++;
        }
        if(spfa(1)){
            printf("-1\n");
            continue;
        }
        if(dis[N] == inf) printf("-2\n");
        else printf("%d\n",dis[N]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值