差分约束系统【模板】

来源:互联网 发布:东风白杨民兵 知乎 编辑:程序博客网 时间:2024/05/27 20:34

差分约束系统:如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如 xj - xi<= bk ( i , j ∈ [1,n],k ∈ [1,m]),则称其为差分约束系统。 
例如如下的约束条件: 
X1 - X2 <= 0 X1 - X5 <= -1 
X2 - X5 <= 1 X3 - X1 <= 5 
X4 - X1 <= 4 X4 - X3 <= -1 
X5 - X3 <= -3 X5 - X4 <= -3 
全都是两个未知数的差小于等于某个常数(大于等于也可以,因为左右乘以-1就可以化成小于等于)。这样的不等式组就称作差分约束系统。 
差分约束系统求解过程: 
1.新建一个图,N个变量看作N个顶点,M个约束条件作为M条边。每个顶点Vi分别对于一个未知量,每个有向边对应两个未知量的不等式。 
2.为了保证图的连通性,在图中新加一个节点Vs,图中每个节点Vi都能从Vs可达,建立边w(Vs,Vi) = 0。 
3.对于每个差分约束Xj - Xi <= Bk(这里是小于等于号),则建立边w(Xi,Xj) = Bk。 
4.初始化Dist[] = INF,Dist[Vs] = 0. 
5.求解以Vs为源点的单源最短路径,推荐用SPFA,因为一般可能存在负值。 
如果图中存在负权回路,则该差分约束系统不存在可行解。 
Vs到某点如果不存在最短路径,即最短路为INF,则对于该点表示的变量可以取任意值,都能满足差分约束的要求,如果存在最短路径,则得到该变量的最大值。 
上述过程最终得到的解为满足差分约束系统各项的最大值。 
注意点: 
1. 如果要求最大值想办法把每个不等式变为标准 x - y <= k 的形式,然后建立一条从 y 到 x 权值为 k 的边,变得时候注意 x - y < k => x - y <= k-1。 
2. 如果要求最小值的话,变为 x - y >= k 的标准形式,然后建立一条从 y到 x 权值为 k 的边,求出最长路径即可。 
3. 如果权值为正,用Dijkstra,SPFA,BellmanFord都可以,如果为负不能用Dijkstra,并且需要判断是否有负环,有的话就不存在。

<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<iostream></span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<algorithm></span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<cstdio></span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<cstring></span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<queue></span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define INF 0x7fffffff</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">namespace</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> MAXN = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1100</span>;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> MAXM = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30030</span>;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> EdgeNode{    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> to;    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w;    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> next;}Edges[MAXM];<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> AddEdges(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> u,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> v,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w){    Edges[id].to = v;    Edges[id].w = w;    Edges[id].next = Head[u];    Head[u] = id++;}<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> SPFA(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> s,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> N){    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> ans = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">memset</span>(vis,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(vis));    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">memset</span>(outque,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(outque));    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; i <= N; ++i)        Dist[i] = INF;    Dist[s] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;    vis[s] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;    <span class="hljs-stl_container" style="box-sizing: border-box;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>></span> Q;    Q.push(s);    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>( !Q.empty() )    {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> u = Q.front();        Q.pop();        vis[u] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;        outque[u]++;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(outque[u] > N+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//如果出队次数大于N,则说明出现负环</span>        {            ans = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;        }        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = Head[u]; i != -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; i = Edges[i].next)        {            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> temp = Dist[u] + Edges[i].w;            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(temp < Dist[Edges[i].to])            {                Dist[Edges[i].to] = temp;                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>( !vis[Edges[i].to])                {                    vis[Edges[i].to] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;                    Q.push(Edges[i].to);                }            }        }    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(ans == -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//出现负权回路,不存在可行解</span>        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"-1\n"</span>);    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(Dist[N] == INF) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//可取任意值,都满足差分约束系统</span>        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"-2\n"</span>);    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%d\n"</span>,Dist[N]);  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//求使得源点 s 到 终点 t 的最大的值</span>}<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(){    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> N,ML,MD,u,v,w;    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(~<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">scanf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%d%d%d"</span>, &N, &ML, &MD))    {        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">memset</span>(Head,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(Head));        id = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < ML; ++i)        {            <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">scanf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%d%d%d"</span>,&u,&v,&w);            AddEdges(u,v,w);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//建边 u - v <= w</span>        }        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < MD; ++i)        {            <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">scanf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%d%d%d"</span>,&u,&v,&w);            AddEdges(v,u,-w);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//建边 v - u <= w</span>        }<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//这里不加也可以</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//        for(int i = 1; i < N; ++i)</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//            AddEdges(i+1,i,0);</span>        SPFA(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,N);  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//求使得源点 s 到 终点 t 的最大的值</span>    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;}</code>
0 0