Loading

Capitalism

算法

差分约束

观察到 \(a_i\) 最后是确定唯一的 + 我是从差分约束专题来的 ,考虑对于 \(a_i\) 的约束条件进行差分约束。

转化约束条件

观察到,

\[\left\{ \begin{array}{lr} b = 0, \lvert {a_u - a_v} \rvert = 1, & \\ b = 1, a_u + 1 = a_v & \end{array} \right. \]

\[\Downarrow \]

\[\left\{ \begin{array}{lr} a_u, a_v \in \mathbb{Z}, & \\ b = 0, a_u + 1 \geq a_v \text{ 且 } a_v + 1 \geq a_u \text{ 且 } a_u \neq a_v, & \\ b = 1, a_u + 1 \geq a_v \text{ 且 } a_u + 1 \leq a_v & \end{array} \right. \]

都可以作为约束条件。
但是需要解决 \(a_u = a_v\) 的情况。

观察到原图如果不是一个二分图(存在奇环),那么不管对于环上每一边 \((u, v)\) 的权值取 \(-1\) 还是 \(1\) ,必不可能使 \(\sum w = 0\)
所以原图一定是二分图。

处理方式

根据二分图性质处理

在没有奇环的情况下,一条边相连的两个点的 \(dis\) 一定奇偶性不同 ( \(w \in \{ 1, -1 \}\) 每次跑一条边必定改变 \(dis\) 奇偶性,只有存在奇环时,才能出现奇偶性不变的情况),是不可能出现 \(a_i=a_j\) 的。
因此可以直接跑一遍即可。

终于搞懂了, 耗时 \(2 \text{ } \rm{hours}\)

二分图 trick

令当前考虑的边为 \((u, v)\), 其中 \(u\) 为偶数点,
\(a_u = 2b_u, a_v = 2b_v + 1\)
即可将 \(\lvert {a_u-a_v}\rvert \leq 1\) 转化为 \(b_v\leq b_u\leq b_v+1\) ,这样差值内的整数就只有 \(0/1\) 了。
这个思路来源于 ningago 的题解

跑差分约束

无论如何,最后枚举 \(0\) 势点,跑差分约束即可。
不会的见 差分约束模板

最短路应用

具体见 FutaRimeWoawaSete 的题解

代码

#include <bits/stdc++.h>
const int MAXM = 2e3 + 20;
const int MAXN = 2e2 + 20;

int n, m;

class Graph_class
{
private:
    /*染色法判定二分图*/
    int Color[MAXN];
    bool dfs(int Now, int Colour)
    {
        Color[Now] = Colour;
        for (int i = head[Now]; ~i; i = Edge[i].next) {
            int NowTo = Edge[i].to;
            int Next_Colour = 3 - Colour;
            if(!Color[NowTo] && !dfs(NowTo, Next_Colour)) {
                return false;
            }else if(Color[NowTo] && Color[NowTo] != Next_Colour) {
                return false;
            }
        }
        return true;
    }

public:
    struct Edge_Node
    {
        int to, w;
        int next;
    } Edge[MAXM << 1];
    int Edge_Cnt = 0;
    int head[MAXN];
    void head_init() { for(int i = 1; i <= n; i++) head[i] = -1; }

    void addedge(int u, int v, int w)
    {
        Edge[++Edge_Cnt].to = v, Edge[Edge_Cnt].w = w, Edge[Edge_Cnt].next = head[u];
        head[u] = Edge_Cnt;
    }

    bool IS_BG()
    {
        return dfs(1, 1);
    }
} Graph;

class Solve_Class
{
private:
    std::queue<int> Q;
    int Neg[MAXN]; // 判断负环
    bool inq[MAXN];
    int dis[MAXN];

    void init()
    {
        while(!Q.empty()) Q.pop();
        memset(Neg, 0, sizeof(Neg));
        memset(inq, false, sizeof(inq));
        memset(dis, 0x3f, sizeof(dis));
    }
    
    bool spfa(int Start)
    {
        init();
        Q.push(Start), Neg[Start]++, inq[Start] = true, dis[Start] = 0;

        while(!Q.empty())
        {
            int Now = Q.front();
            Q.pop();
            inq[Now] = false;
            for (int i = Graph.head[Now]; ~i; i = Graph.Edge[i].next) {
                int NowTo = Graph.Edge[i].to, NowW = Graph.Edge[i].w;
                if(dis[NowTo] > dis[Now] + NowW) {
                    dis[NowTo] = dis[Now] + NowW;
                    if(!inq[NowTo]) Q.push(NowTo), inq[NowTo] = true, Neg[NowTo]++;
                    if(Neg[NowTo] > n) return true;
                }
            }
        }

        return false;
    }

public:
    void solve()
    {
        int Ans_Val = -1;
        int Ans_S[MAXN];
        for (int i = 1; i <= n; i++) {
            /*注意这里只要有负环, 必定无解*/
            if(spfa(i)) {
                printf("NO");
                exit(0);
            }
            int Now_Val = 0;
            for (int i = 1; i <= n; i++)
                Now_Val = std::max(Now_Val, dis[i]);
            if(Now_Val > Ans_Val) {
                Ans_Val = Now_Val;
                for (int i = 1; i <= n; i++) {
                    Ans_S[i] = dis[i];
                }
            }
        }

        printf("YES\n");
        printf("%d\n", Ans_Val);
        for (int i = 1; i <= n; i++)
            printf("%d ", Ans_S[i]);
    }
} Sol;

int main()
{
    scanf("%d %d", &n, &m);
    Graph.head_init();
    for (int i = 1; i <= m; i++) {
        int u, v, type;
        scanf("%d %d %d", &u, &v, &type);
        if(type == 0) Graph.addedge(u, v, 1), Graph.addedge(v, u, 1);
        else Graph.addedge(u, v, 1), Graph.addedge(v, u, -1);
    }

    /*判断是否合法*/
    if(!Graph.IS_BG())
        printf("NO");
    else
    {
        Sol.solve();
    }

    return 0;
}

总结

边权 \(\in \{ 1, -1 \}\) 时,拥有一些特殊的性质。

对于绝对值不等式,考虑变形 trick 。

posted @ 2024-11-11 11:01  Yorg  阅读(45)  评论(0)    收藏  举报