[BZOJ3436]小K的农场(差分约束)

来源:互联网 发布:单片机论坛网430 编辑:程序博客网 时间:2024/05/18 03:07

题目描述

传送门

题目大意:n个点每一个点有一个权,有m个限制:1 a b cd(a)-d(b)>=c; 2 a b cd(a)-d(b)<=c;3 a bd(a)=d(b),判断是否有可行解

题解

对于三个限制移项啥的可以化出来一些不等式:d(b)<=d(a)-c;d(a)<=d(b)+c;d(b)<=d(a),d(a)<=d(b)
对于一个形如d(x)<=d(y)+z的等式,连边y->x,z构造出最短路模型
这道题没有源点,所以强行加一个源点0,然后因为要从源点连向每一个点,所以强行d(i)<=d(0)
设d(0)=0,虽然求出来的所有的d都是非正数,但是所有的d同时加上一个数都是可行解,所以没有影响;只需要看图中是否有负权环即可
用深搜版spfa判断负环快很多很多…

代码

普通spfa

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<queue>using namespace std;#define N 10005#define E 50005int n,m,ans;int tot,point[N],nxt[E],v[E],c[E];int dis[N],cnt[N];bool vis[N];queue <int> q;void add(int x,int y,int z){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;}int spfa(){    memset(dis,127,sizeof(dis));    dis[0]=0;vis[0]=1;cnt[0]=1;q.push(0);    while (!q.empty())    {        int now=q.front();q.pop();        vis[now]=0;        for (int i=point[now];i;i=nxt[i])            if (dis[v[i]]>dis[now]+c[i])            {                dis[v[i]]=dis[now]+c[i];                if (!vis[v[i]])                {                    ++cnt[v[i]];                    if (cnt[v[i]]>n) return 0;                    vis[v[i]]=1;                    q.push(v[i]);                }            }    }    return 1;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;++i)    {        int opt,a,b,c;scanf("%d",&opt);        if (opt==1)        {            scanf("%d%d%d",&a,&b,&c);            add(a,b,-c);        }        else if (opt==2)        {            scanf("%d%d%d",&a,&b,&c);            add(b,a,c);        }        else        {            scanf("%d%d",&a,&b);            add(a,b,0);add(b,a,0);        }    }    for (int i=1;i<=n;++i) add(0,i,0);    ans=spfa();    if (!ans) puts("No");    else puts("Yes");}

深搜版spfa

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<queue>using namespace std;#define N 10005#define E 50005int n,m;int tot,point[N],nxt[E],v[E],c[E];int dis[N];bool vis[N],flag;queue <int> q;void add(int x,int y,int z){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;}void spfa(int x){    vis[x]=1;    for (int i=point[x];i;i=nxt[i])        if (dis[v[i]]>dis[x]+c[i])        {            dis[v[i]]=dis[x]+c[i];            if (vis[v[i]])            {                flag=1;                return;            }            spfa(v[i]);            if (flag) return;        }    vis[x]=0;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;++i)    {        int opt,a,b,c;scanf("%d",&opt);        if (opt==1)        {            scanf("%d%d%d",&a,&b,&c);            add(a,b,-c);        }        else if (opt==2)        {            scanf("%d%d%d",&a,&b,&c);            add(b,a,c);        }        else        {            scanf("%d%d",&a,&b);            add(a,b,0);add(b,a,0);        }    }    for (int i=1;i<=n;++i) add(0,i,0);    memset(dis,127,sizeof(dis));dis[0]=0;    flag=0;spfa(0);    if (!flag) puts("Yes");    else puts("No");}
0 0
原创粉丝点击