P3275 [SCOI2011]糖果

原题链接
考察:差分约束+SPFA
引入:
什么是差分约束?
差分约束系统是一个n元一次不等式组.

它的作用包括:

(1) 求一组不等式的可行解

(2) 求一组不等式的最大值或最小值.(每个变量的最值)

不等式的格式是 : Xi \(\leq\) X j + C (C为常数)

这里联想到最短路问题,如果图中不存在负环,那么在求完最短路之后,对于每一条边 i ---> j,必然满足 :

dist[j] \(\leq\) dist[i] + road[i].w 注意到这个等式与差分约束的不等式很像,所以对于差分约束求可行解问题,我们都可以转化为单源最短路问题.

但是源点是不能任取的,我们要求从源点出发,一定能遍历到所有的边.那么怎样才能满足要求呢? 一般是建立虚拟源点

1.求可行解的步骤

(1) 将每个不等式转化为一条边.

(2) 找一个超级源点,使得该源点一定可以遍历到所有边.

(3) 从源点求单源最短路.

注意:如果图中存在负环,那么不等式一定矛盾,这两者等价

2.最长路与最短路的区别

求完所有点的最短路后, dist[j] \(\leq\) dist[i] + road[i].w . 所以 Xi \(\leq\) X j + C

与之对应求完所有点的最长路后, dist[j] \(\geq\) dist[i] + road[i].w . 对应 X i \(\geq\) X j + C

3.求最大、最小值

  • 如果求最小值那么就是求最长路
  • 如果求最大值那么就是求最短路

如果是求最值问题,一般都会有一个绝对值,即 : X i \(\leq\) C 或X \(\geq\) C,否则X的取值之间都是相对关系.如果X 1 ,X 2 ,X i ...是可行解,那么X+d也是可行解.

问题:如何转化X i \(\leq\) C为图论的一条边?

方法:建立虚拟源点X 0 , 设X 0 = 0 , 那么 X i \(\leq\) C ----> X i \(\leq\) X 0 + C .

X i \(\leq\) X 0 + C 适用于求最大值的情况

那么如何求最大值?

枚举所有从X i 出发的不等式链.

X i \(\leq\) X j + C j \(\leq\) Xk + C k \(\leq\) ... \(\leq\) X 0 +C j + C j +一堆常数

所有不等式链取最小值即X i 的最大值.

每一条不等式链,都是从0出发到达X i 的一条路径,根据上面的结论,X i 的最大值就是最短路径的长度.

思路:
将每个条件化为不等式,因为要取最小所以边值是1或0.然后套差分约束的板子.环的长度是n2 ,所以需要开long long

#include <iostream>
#include <queue>
#include <cstring>
#include <stack>
using namespace std;
typedef long long LL;
const int N = 100010;
int h[N],n,m,idx,cnt[N];
bool st[N];
LL dist[N];
struct Road{
    int fr,to,ne,w;
}road[N*3];
void add(int a,int b,int w)
{
    road[idx].w = w,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
LL spfa()
{
    for(int i=1;i<=n+1;i++) dist[i] = -1e14;
    stack<int> q;
    dist[0] = 0;
    q.push(0);
    st[0] = 1;
    int count = 0;
    while(q.size())
    {
        int u = q.top();
        q.pop();
        st[u] = 0;
        for(int i=h[u];~i;i=road[i].ne)
        {
            int v = road[i].to;
            if(dist[v]<dist[u]+road[i].w)
            {
                dist[v] = dist[u]+road[i].w;
                cnt[v] = cnt[u]+1;
                if(cnt[v]>=n+1) return -1;
                if(!st[v]) q.push(v),st[v] = 1;
            }
        }
    }
    LL res = 0;
    for(int i=1;i<=n;i++) res+=dist[i];
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    while(m--)
    {
        int x,a,b; scanf("%d%d%d",&x,&a,&b);
        if(x==1) add(a,b,0),add(b,a,0);
        else if(x==2) add(a,b,1);
        else if(x==3) add(b,a,0);
        else if(x==4) add(b,a,1);
        else add(a,b,0);
    }
    for(int i=1;i<=n;i++) add(0,i,1);
    printf("%lld\n",spfa());
    return 0;
}
posted @ 2021-05-08 00:01  acmloser  阅读(51)  评论(0编辑  收藏  举报