poj3169(我的第一个查分约束!)

题目大意:有N头奶牛,编号从1到N,从左到右站成一排。有些奶牛互相喜欢,有些奶牛互相不喜欢。互相喜欢的奶牛有要求:互相喜欢的奶牛之间的距离不能超过一个值;同样,互相讨厌的奶牛之间的距离不能小于一个值。现在求在这样的要求下,1~N之间的距离的最大值。如果无法满足所有要求就输出-1,如果有无限种情况就输出-2,否则输出最大值。

 

输入:                                           输出:          

4 2 1                          27
1 3 10
2 4 20
2 3 3

解释:有四头牛,有两对互相喜欢,一对互相讨厌。两队喜欢的分别是1和3,要求距离不能大于10。另外一对是2,4,要求为20。讨厌的的一对是2,3,距离得不小于3。所以最大值为27。
(1和2的距离为7,2和3的距离为3,3和4的距离为17)

--->差分约束
那么现在来分析这道题。
假设互相喜欢的两头牛是a和b,那么dis[b]-dis[a]<=D(D为要求的值,dis[a]表示a到1的距离)
互相讨厌的是c和d,那么dis[d]-dis[c]>=D ----> dis[c]-dis[d]<=-D
因为距离是递增的,所以还有一个条件,s[i]-s[i-1]>=0 ----> s[i-1]-s[i]<=0
不等式已经列出来了,现在可以建图了。(详见代码)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=1000+10;
const int INF=0x3f3f3f3f;

int n,ML,MD,cnt;
int dis[MAXN],head[MAXN*MAXN],num[MAXN];
bool vis[MAXN]; 
struct node{
    int v,w,next;
}e[MAXN*MAXN];

int SPFA()
{
    queue<int>q;
    memset(dis,INF,sizeof(dis));
    memset(num,0,sizeof(num));
    memset(vis,0,sizeof(vis));
    q.push(1);
    dis[1]=0;
    num[1]=1;
    vis[1]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v,w=e[i].w;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                if(!vis[v]){
                    if(++num[v]>n)
                        return -1;
                }
                q.push(v);
                vis[v]=1;
            }
        }
    }
    if(dis[n]==INF)    return -2;
    else return dis[n];
}

void Add(int a,int b,int c)
{
    e[cnt].v=b;
    e[cnt].w=c;
    e[cnt].next=head[a];
    head[a]=cnt++;
}

int main(void)
{
    
    while(~scanf("%d%d%d",&n,&ML,&MD)){
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)
            Add(i,i-1,0);            //升序 所以  s[i]-s[i-1]>=0  ->  s[i-1]-s[i]<=0
                                    //我们可以把s[i]近似的看做i 
        for(int i=1,a,b,c;i<=ML;i++){
            scanf("%d%d%d",&a,&b,&c);
            if(a>b)    swap(a,b);
            Add(a,b,c);    
        }
                        //a like b,so b-a<=c  ->   b<=a+c
        for(int i=1,a,b,c;i<=MD;i++){
            scanf("%d%d%d",&a,&b,&c);
            if(a>b)    swap(a,b);
            Add(b,a,-c);
        }
                        //the same   b-a>=c   ->   a-b<=-c
        int ans=SPFA();
        printf("%d\n",ans);
    }
        return 0;
}//SnowCabbage

 

 
posted @ 2018-09-20 11:15  雪国大白菜  阅读(183)  评论(0编辑  收藏  举报