【BZOJ】1731: [Usaco2005 dec]Layout 排队布局

【题意】给定按编号顺序站成一排的牛,给定一些约束条件如两牛距离不小于或不大于某个值,求1和n的最大距离。无解输出-1,无穷解输出-2。

【算法】差分约束+最短路

【题解】图中有三个约束条件,依次分析:

①坐标顺序和编号顺序一致【一定一定要记得这个约束条件】

xi-xi-1>=0

i向-1连边0

②两牛距离不大于距离L

xj-xi<=L

i向j连边L

③两牛距离不小于距离D

xj-xi>=D即xi-xj<=-D

j向i连边-D

 

连边完毕,通过跑最短路得到起点和终点的直接约束xT-xS<=d,d就是1到n的最大值。

注意循环队列while(head!=tail)

检测负环可以用【点的入队次数>n】和【到点步数>n】两种方法。一起用也资瓷=w=。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1010;
int n,m,k,tot=0;
int first[maxn],step[maxn],q[maxn],d[maxn];
bool vis[maxn];
struct edge{int v,w,from;}e[maxn*maxn];
void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
bool spfa(){
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    int head=0,tail=1;
    q[head]=1;vis[1]=1;d[1]=0;
    bool p=1;
    while(head!=tail){//
        int x=q[head++];if(head>n)head=0;
        for(int i=first[x];i;i=e[i].from)if(d[x]+e[i].w<d[e[i].v]){
            d[e[i].v]=d[x]+e[i].w;
            step[e[i].v]=step[x]+1;
            if(step[e[i].v]>n){p=0;break;}
            if(!vis[e[i].v]){
                if(d[e[i].v]<d[q[head]]){head--;if(head<0)head=n;q[head]=e[i].v;}
                else{q[tail++]=e[i].v;if(tail>n)tail=0;}
                vis[e[i].v]=1;
            }
        }
        vis[x]=0;
    }
    return p;
}
            
int main(){
    scanf("%d%d%d",&n,&m,&k);
    int u,v,w;
    for(int i=2;i<=n;i++)insert(i,i-1,0);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        if(u>v)swap(u,v);
        insert(u,v,w);
    }
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&u,&v,&w);
        if(u>v)swap(u,v);
        insert(v,u,-w);
    }
    if(spfa()){
        if(d[n]==0x3f3f3f3f)printf("-2");else printf("%d",d[n]);
    }else printf("-1");
    return 0;
}
View Code

 

posted @ 2017-10-19 07:31  ONION_CYC  阅读(230)  评论(0编辑  收藏  举报