Differential constraint system

Keywords: Graph Theory

Negative ring:

Because the negative ring must be shorter and shorter, but when all points on a graph are selected, it must not be the shortest path. Therefore, we can think about how to deal with negative rings from this point:

The only way to deal with negative rings is \ (\ text{SPFA} \), \ (\ text{dijkstra} \) is not available.

When we update the edge weight each time, if it is a positive edge, we can only update the next answer once, so if there is a negative ring, we update the next answer many times.

Each time the shortest path transfer occurs, we also transfer the number of points included in the shortest path, which is:

if(dis[y]>dis[x]+z){
    dis[y]=dis[x]+z;
    cnt[y]=cnt[x]+1;//Number of points included in the transfer
    if(cnt[y]>=n) {flag=1;return;}//It shows that there is a negative ring in the figure. At this time, it returns directly
    if(!vis[y]){vis[y]=1; q.push(y);}
}

In addition to this, other four breaks are the same as normal, just write normally.

Differential constraint:

Introduce from a question:

P5960 differential constraint algorithm

Given \ (n \) variables and \ (m \) constraints, using \ (x_i-x_j\leq c_k \), it is necessary to find a set of solutions so that all constraints are met.

analysis:

Deform the above formula: \ (x_i\leq c_k+x_j \), which is very similar to the shortest path formula. Therefore, to solve this problem, we first build a super source point \ (0 \) and connect the source point to each point with an edge with a length of \ (0 \).

Then, for each constraint, connect an edge with length \ (c_k \) from \ (j\rightarrow i \) to represent this constraint.

Therefore, a set of solutions is the shortest path from \ (0 \) point to each point.

code:

// P5960 [template] difference constraint algorithm
#include<bits/stdc++.h>

using namespace std;

const int N=2e5+5;

int nxt[N],ver[N],tot,edge[N],head[N];
int n,m,flag=0;
int dis[N],vis[N],cnt[N];
void add(int x,int y,int z){
    ver[++tot]=y; edge[tot]=z; nxt[tot]=head[x]; head[x]=tot;
}
queue<int> q;
void spfa(int x){
    memset(dis,0x3f3f3f3f,sizeof(dis));
    dis[x]=0,vis[x]=1;
    q.push(x); 
    while(!q.empty()){
        int x=q.front(); q.pop();
        vis[x]=0;
        for(int i=head[x];i;i=nxt[i]){
            int y=ver[i],z=edge[i];
            if(dis[y]>dis[x]+z){
                dis[y]=dis[x]+z;
                cnt[y]=cnt[x]+1;
                if(cnt[y]>=n+1) {flag=1;return;}//It shows that there is a negative ring in the figure
                if(!vis[y]){
                    q.push(y); vis[y]=1;
                }
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) add(0,i,0);
    for(int i=1,x,y,z;i<=m;i++){
        scanf("%d%d%d",&y,&x,&z);//It's not building a side
        add(x,y,z);
    }
    spfa(0);
    if(flag==1) puts("NO");
    else for(int i=1;i<=n;i++) printf("%d ",dis[i]); puts("");
    system("pause");
    return 0;
}

In this way, we find that these formulas can be satisfied at the same time by building the edge to find the shortest path form, which is called differential constraint system.

Edge construction method:

The \ (z \) here are non negative numbers:

  1. \(y-x \leq z \), so this is to find the shortest path. It can be understood as follows: \ (x,y \) has found the shortest path, so the difference between the shortest paths will not be longer than the path between two points.
    If they are equal, this is the shortest path. Because the path length is \ (dis[y]-dis[x] \), it means that this edge is a directed edge with the weight of \ (z \) from the edge of \ (x\rightarrow y \).

  2. \(y-x \geq z \), then you are seeking the longest path. As above, the difference between the longest paths of two points will not be longer than the path of two points. The edge is also a directed edge whose weight is \ (z \) from \ (x\rightarrow y \).

  3. \(x-y=z \), split into two constraints, namely: \ (x\rightarrow y \), the edge weight is \ (0 \), \ (y\rightarrow x \), and the edge weight is \ (0 \).

Pay attention to the order of connecting edges. It's easy to understand if you write too much.

Judge whether it is true:

The way to judge whether the differential constraints can be fully established is to judge the negative ring. But note: because we added a super source point, the standard of negative ring is \ (n+1 \) points. Note here.

Create super source:

For some problems, the edge weights from the super source point to other points are also different. Some requirements must be, so the edge right is the minimum limit point. Otherwise, a point with zero edge weight is established.

Example:

[SCOI2011] candy

Meaning:

Give you five operations. Each operation gives two restrictions on the weight and finds the sum of the weight.

analysis:

Obviously, this problem limits the size relationship between points, so it is easy to think of differential constraints.

First, a path with a weight of \ (1 \) is established from the super source point to other points. Because every child must have.

Looking at the formulas, we find that they are all formulas of type \ (y-x \geq z \), so we are looking for the longest path.

Pay attention to judge the negative ring, set up the edge method, list the inequalities, and build it.

code:

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=6e5+5;

int nxt[N],ver[N],tot,edge[N],head[N];
int n,m,flag=0,ans;
int dis[N],vis[N],cnt[N];
void add(int x,int y,int z){
    ver[++tot]=y; edge[tot]=z; nxt[tot]=head[x]; head[x]=tot;
}
queue<int> q;

signed main(){
    cin>>n>>m;
    for(int i=1,op,x,y;i<=m;i++){
        scanf("%lld%lld%lld",&op,&x,&y);
        if((op==2||op==4)&&(x==y)) flag=1;
        if(op==1) add(x,y,0),add(y,x,0);
        else if(op==2) add(x,y,1);
        else if(op==3) add(y,x,0);
        else if(op==4) add(y,x,1);
        else if(op==5) add(x,y,0);
    }
    if(flag==1){puts("-1");return 0;}       
    for(int i=n;i>=1;i--) add(0,i,1);    
    dis[0]=0,vis[0]=1;
    q.push(0); 
    while(!q.empty()){
        int x=q.front(); q.pop();
        vis[x]=0;
        for(int i=head[x];i;i=nxt[i]){
            int y=ver[i],z=edge[i];
            if(dis[y]<dis[x]+z){
                cnt[y]=cnt[x]+1;
                dis[y]=dis[x]+z;
                if(cnt[y]==n+1){puts("-1");return 0;}
                if(!vis[y]){
                    q.push(y); vis[y]=1;
                }
            }
        }
    }
    for(int i=1;i<=n;i++) ans+=dis[i];
    cout<<ans<<endl;             
    
    system("pause");

    return 0;
}

Posted by spartan7 on Wed, 03 Nov 2021 17:40:54 -0700