差分约束系统 糖果Candy

来源:互联网 发布:证券开户数据 编辑:程序博客网 时间:2024/05/18 01:59

差分约束系统

有一个人他是这样说的
我们有如下几个式子:
A-B<=x —-> A最多比B大x
A-C<=y —-> A最多比C大y
B-C<=z —-> B最多比C大z
所有的约束条件反映了一个问题:
一个数不可能过大,因为某个数可能至多比某个数大k,所以这是一类有最大值问题。
那么假如对于A-B<=x ,我们由B向A连一条大小为x的边。
对于所有等式,由C向B连一条z的边,B向A连一条x的边,C向A连一条y的边。
我们看一下,C到A的路径有两条,一条长度为y的代表A至多比C大y。
另一条路径C–>B–>A的长度为x+z,代表A至多比C大x+z。
最后我们发现C到A的最短路径就是C至多比A大多少,即有最大值限制。
跑SPFA求最短路,记得判断负权回路。

可是另一个人他是这样说的
A-B>=x —-> A至少比B大x
A-C>=0 —-> A至少和C相等
B-C>=0,C-B>=0 —-> B的值等于C的值
所有的约束条件也反映了一个问题:
一个数不可能过小,因为某个数至少要比某个数大,所以这是一类有最小值问题。
我们对于A-B>=x,我们由B向A连一条大小为x的边。
我们从B走向A的最长(若有正环代表循环约束约束失败)路径就是A至少比B大多少。
我们跑SPFA最长路径,记得判断正环。

[SCOI2011][bzoj2330] 糖果Candy

1:A=B -> A>=B,B>=A
2:A B>=A+1
3:A>=B
4:A>B -> A>=B+1
5:A<=B
根据上述条件连边,spfa求最长路判断有无正权环即可。因为每个人都要分得糖果,所以由超级源0点向每个点连长为1的边,最后答案为最短路之和。

需要注意的是,数据中有链的情况,如果使用边表需要倒序加入如果使用vector的方式需要正序加入,目的是使按照1-n的顺序进行spfa,以免时间退化为O(n^2)。

Attention!!! 这是一个我WA掉的代码 判正环有问题 求大神指点

  #include<cstdio>#include<cstring>#include<algorithm>#include<algorithm>struct info{int to,nex,val;}e[400005];int tt,x,y,z,i,n,k,last[100005],q[3000005],num[100005],d[100005];bool bo[100005];long long ans;void add(int x,int y,int z){ tt++;  e[tt].to=y;  e[tt].val=z;  e[tt].nex=last[x];  last[x]=tt;}bool spfa(){int i,h,t,u,v;  h=0;t=1;bo[0]=true;q[0]=0;num[0]=1;  for (i=n;i>=1;i--) d[i]=1,q[t++]=i;  while (h<=t)  { u=q[h];h++;bo[u]=false;    for (i=last[u];i!=0;i=e[i].nex)    { v=e[i].to;      if (d[u]+e[i].val>d[v])      { d[v]=d[u]+e[i].val;        if (num[v]>n) return false;        if (!bo[v])        { bo[v]=true;num[v]++;          q[t]=v;t++;          }      }    }  }  return true;}int main(){ scanf("%d%d",&n,&k);  for (i=1;i<=k;i++)  { scanf("%d%d%d",&z,&x,&y);    if (x==y&&(z==2||z==4)) {printf("-1");return 0;}    if (z==1)    { add(x,y,0);      add(y,x,0);    }    else if (z==2) add(x,y,1);    else if (z==3) add(y,x,0);    else if (z==4) add(y,x,1);    else add(x,y,0);  }  if (!spfa()) ans=-1;  else for (i=1;i<=n;i++) ans+=d[i];  printf("%lld",ans);} 
0 0
原创粉丝点击