差分约束

烈酒焚心 提交于 2020-03-03 20:45:54

如果一个不等式组由 n 个变量和 m 个约束条件组成,形成 m 个形如x[ j ]-x[ i ]≤k(i,j∈[1,n] 且 k 为常数)的不等式,则称其为差分约束系统。换句话说,差分约束系统就是求解一组变量的不等式组的算法。

连边后求最短路
将x[ j ]x[ i ]k 变形为 x[ j ]​≤k+x[ i ],即从 i 到j 连一条边权为 k 的边。加入超级源点后求最短路,得到xi0 所有 x 最大解。

连边后求最长路
x[ j ]x[ i ]k 变形为 x[ i ]​ ≤ x[ j ]-k,即从 j 到 i 连一条边权为 k 的边。加入超级源点后求最长路,得到 xi0 所有 x 最小解

 

 1 #include<iostream>
 2 #include<queue>
 3 #include<cstdio> 
 4 #include<cstring>
 5 using namespace std;
 6 #define N 5005
 7 #define M 11000
 8 int n,m,cnt;
 9 int head[N];
10 struct edge{
11     int to,w,nxt;
12 }e[M];
13 void add(int u,int v,int w){
14     e[++cnt].w=w;
15     e[cnt].to=v;
16     e[cnt].nxt=head[u];
17     head[u]=cnt;
18 }
19 int dis[5005],tot[5005];//tot为入队次数
20 bool vis[N];
21 queue<int>q;
22 bool spfa(){
23     for(int i=1;i<=n;i++) dis[i]=0x7ffffff;
24     memset(vis,0,sizeof(vis));
25     q.push(0);dis[0]=0;vis[0]=1;
26     while(q.size()){
27         int u=q.front();q.pop();
28         vis[u]=0;
29         for(int i=head[u];i;i=e[i].nxt){
30             int v=e[i].to;
31             if(dis[v]>dis[u]+e[i].w){
32                 dis[v]=dis[u]+e[i].w;
33                 if(!vis[v]){
34                     vis[v]=1;q.push(v);
35                 }
36                 tot[v]++;
37                 if(tot[v]==n)return 0;
38             }
39         }
40     } 
41     return 1;
42 }
43 int main(){
44     scanf("%d%d",&n,&m);
45     for(int i=1;i<=n;i++)add(0,i,0);
46     for(int i=1;i<=m;i++){
47         int a,b,c;
48         scanf("%d%d%d",&a,&b,&c);
49         add(b,a,c);
50     }
51     if(!spfa())
52         printf("NO");
53     else
54         for(int i=1;i<=n;i++)
55             printf("%d ",dis[i]);
56     return 0;
57 }
code

 

例题:

https://www.luogu.com.cn/problem/P1250   

poj1201 

(也可用贪心和线段树优化)

跑最长路

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1000005;
 4 const int M = 1000005;
 5 int n,m;
 6 int dis[N];
 7 bool vis[N];
 8 int head[N],num;
 9 struct Edge{
10     int to,next,w;
11 }e[M];
12 void add(int u,int v,int w){
13     e[++num].w=w;
14     e[num].to=v;
15     e[num].next=head[u];
16     head[u]=num;
17 }
18 void spfa(int x){
19     queue<int> q;
20     q.push(x);
21     for(int i=0;i<=n+1;i++)dis[i]=1;
22     dis[x]=0;vis[x]=1;
23     while(!q.empty()){
24         int u=q.front();q.pop();
25         vis[u]=0;
26         for(int i=head[u];i;i=e[i].next){
27             int v=e[i].to;
28             if(dis[v]>dis[u]+e[i].w){
29                 dis[v]=dis[u]+e[i].w;
30                 if(!vis[v]){
31                     q.push(v);
32                     vis[v]=1;               
33                 }
34             }
35         }
36     }
37 }
38 int main(){
39     int a,b,c,minn=0x3f3f3f3f;
40     memset(head,-1,sizeof(head));
41     cin>>n>>m;
42     int y=n+1;
43     for(int i=0;i<=n;i++) add(y,i,0);
44     for(int i=1;i<=m;i++){
45         cin>>a>>b>>c;
46         add(b,a-1,-c);
47     }
48     for(int i=1;i<=n;i++){
49         add(i-1,i,1);
50         add(i,i-1,0);
51     }
52     spfa(y);
53     for(int i=0;i<=n;i++)
54         minn=min(minn,dis[i]);
55     cout<<dis[n]-minn<<endl;
56     return 0;
57 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!