差分约束系统 糖果Candy

差分约束系统

有一个人他是这样说的
我们有如下几个式子:
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
#include
#include
#include
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);
} 

你可能感兴趣的:(OI解题报告)