图论训练之六

Posted wzxbeliever

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论训练之六相关的知识,希望对你有一定的参考价值。

https://www.luogu.org/problem/P3275

说说差分约束的套路吧

关于建图的基本规律

1.如x=y,则add(x,y,0), add(y,x,0)

2.如x>y,则add(y,x,1)

3.如x≤y,则add(x,y,0)

4.如x<y,则add(u,v,1)

5.如x≥y,则add(v,u,0)

(其中边权根据题目而定)

最短路边权为负,最长路边权为正,建议都只用最短路

技巧一

小于号那边的为起点

技巧二

统一符号,都为“<=”或都为"<=",方便计算最短路或最长路(注意我说的前后不一定对应)

如果化简后式子和最短路松弛操作相同则为最长路,否则为最短路

技巧三

抠出隐藏条件,就如本题而言,每个小朋友必须得有糖果,即任意x>0,即0为超级源点


#include<bits/stdc++.h>
#define re register
using namespace std;
typedef long long ll;
const ll N = 200011;
const ll inf = 0x3f3f3f3f3f;
ll n, T, cnt, ans, vis[N], len[N], head[N];
struct edge 
    ll to, next, w;
 e[N << 1];
inline void add( ll u, ll v, ll w ) 
    e[++cnt].to = v, e[cnt].w = w,
    e[cnt].next = head[u], head[u] = cnt;


namespace IO 

    inline ll read() 
        ll x = 0; bool f = 0; char ch = getchar();
        for(; !isdigit( ch ); ch = getchar()) f^=( ch == '-' );
        for(; isdigit( ch ); ch = getchar()) x = ( x << 3 ) + ( x << 1 ) + ( ch ^ 48 );
        return f? -x: x;
    

    inline void write( ll x ) 
        if( x < 0 )  putchar( '-' ); x = -x; 
        if( x > 9 ) write( x / 10 );
        putchar( x % 10 | 48 );
    

    inline void wln( ll x )  write( x ); putchar( '\n' ); 



using namespace IO;
inline bool Spfa( ll u ) //dfs版的spfa更好
    vis[u] = 1;
    for( re int i = head[u]; i; i = e[i].next ) 
        if( len[e[i].to] > len[u] + e[i].w ) 
            len[e[i].to] = len[u] + e[i].w;
            if( vis[e[i].to] || !Spfa( e[i].to ) ) return 0;
        
    vis[u] = 0; return 1;


int main() 
    n = read(), T = read();
    while( T-- ) 
        ll opt = read(), a = read(), b = read();
        switch( opt ) 
            case 1: add( a, b, 0 ); add( b, a, 0 ); break;
            case 2: if( a == b ) return !puts("-1"); add( a, b, -1 ); break;//特判两者相等的情况
            case 3: add( b, a, 0 ); break;
            case 4: if( a == b ) return !puts("-1"); add( b, a, -1 ); break;//同理特判
            case 5: add( a, b, 0 ); break;
        
    

    for( int i=n;i>=1;i--) add(0,i,-1),len[i]=inf;len[0] = 0;//超级源点
    if( Spfa(0) ) 
       for(int i=1;i<=n;i++)ans -= len[i];//值为负,所以要减去
        return wln( ans ), 0;
     else return !puts("-1");

以上是关于图论训练之六的主要内容,如果未能解决你的问题,请参考以下文章

图论训练

联合训练图论场

图论专题训练 (更新中)

图论训练之一

图论训练之四

图论训练之七