2014-03-02 09:05:47Morris

[UVA][並查集] 11323 - Satisfying Constraints

Problem A: Satisfying Constraints

Consider the following constraint satisfaction problem. You are given n variables x1, x2, ..., xn and a set of m two-variable linear constraints. Each constraint takes the form axi + bxj = c where a, b, and c are integer constants. Each variable is allowed to take an integer value between 1 and k for some specified constant k.

Your goal is to determine if it is possible to assign an integer value in the valid range to each variable such that all constraints are satisfied.

The number of test cases is given in the first line of the input. Each test case begins with a line containing integers n, m, and k where 1 ≤ n ≤ 1000 is the number of variables, 0 ≤ m &le 10,000 is the number of constraints and 1 ≤ k ≤ 100 is the largest value allowed for the variable assignments. The following m lines each contain 5 integers a,i,b,j, and c where 1 &le i,j ≤ n and 0 &le |a|,|b|,|c| ≤ 10,000,000.

For each test case, output one line containing yes if all constraints are satisfiable and no otherwise.

Sample input

2
2 1 10
3 1 6 2 5
2 1 10
3 1 6 2 9

Output for sample input

no
yes

Zachary Friggstad

題目描述:


給很多方程式,每個變數只能代入 [1, K] 之間的整數,
問有沒有可能存在解。

題目解法:


對於每一個方程式的解 pair,相當於將兩個節點關係連起來。

根據推論關係,如果同一個變數的兩種值可能在同一個集合中時,則這一套的解是不符的。

由於推論關係是雙向的,因此可以看做是一個連通元件。

因此最後要將不可能的連通元件剔除,最後檢查每一個變數,是否存在一種以上的解。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int rank[100005], parent[100005];
void init(int N) {
    for(int i = 0; i <= N; i++) {
        rank[i] = 1, parent[i] = i;
    }
}
int findp(int x) {
    return parent[x] == x ? x : parent[x] = findp(parent[x]);
}
int joint(int x, int y) {
    x = findp(x), y = findp(y);
    if(x == y)
        return 0;
    if(rank[x] > rank[y])
        rank[x] += rank[y], parent[y] = x;
    else
        rank[y] += rank[x], parent[x] = y;
    return 1;
}
int main()  {
    int testcase;
    int error_group[100005];
    int error_test[100005], error_label[100005] = {}, ecases = 1;
    scanf("%d", &testcase);
    while(testcase--) {
        int N, M, K;
        int A, I, B, J, C;
        int i, j, k;
        int NIL; // error group
        int global_solv = 1;
        scanf("%d %d %d", &N, &M, &K);
        NIL = N * K;
        init(N*K);// [0, N-1][0, K-1]
        for(i = N*K; i >= 0; i--)
            error_group[i] = 0;
        for(i = 0; i < M; i++) {
            scanf("%d %d %d %d %d", &A, &I, &B, &J, &C);
            I--, J--;
            int Vi, Vj;
            if(!global_solv)
                continue;
            int ok = 0;
            if(A == 0 && B == 0) {
                ok = (C == 0);
            } else if(A == 0) {
                for(j = 1; j <= K; j++) {
                    if(B * j != C)
                        joint(NIL, J*K + (j-1));
                    else
                        ok = 1;
                }
            } else if(B == 0) {
                for(j = 1; j <= K; j++) {
                    if(A * j != C)
                        joint(NIL, I*K + (j-1));
                    else
                        ok = 1;
                }
            } else {
                if(C%__gcd(A, B) == 0) {
                    for(j = 1; j <= K; j++) {
                        Vi = j, Vj = (C - A * Vi)/B;
                        if(Vj < 1 || Vj > K || A * Vi + B * Vj != C)
                            joint(NIL, I*K + Vi-1);
                        else
                            joint(I*K + Vi-1, J*K + Vj-1), ok = 1;
                        Vj = j, Vi = (C - B * Vj)/A;
                        if(Vi < 1 || Vi > K || A * Vi + B * Vj != C)
                            joint(NIL, J*K + Vj-1);
                        else
                            joint(I*K + Vi-1, J*K + Vj-1), ok = 1;
                    }
                }       
            }
            global_solv &= ok;
        }
        error_group[findp(NIL)] = 1;
        for(i = 0; i < N && global_solv; i++) {
            ecases++;
            for(j = 0; j < K; j++) {
                int p = findp(i*K + j);
                if(error_label[i*K + j] != ecases)
                    error_label[i*K + j] = ecases, error_test[p] = 0;
                error_test[p]++;
                if(error_test[p] > 1)
                    error_group[p] = 1;
            }
        }
        for(i = 0; i < N && global_solv; i++) {
            int ok = 0;
            //printf("x%d = ", i+1);
            for(j = 0; j < K; j++) {
                int p = findp(i*K + j);
                if(error_group[p] == 0) {
                    ok = 1;
                    //printf("%d", j+1);
                    break;
                }
            }
            //puts("");
            global_solv &= ok;
        }
        puts(global_solv ? "yes" : "no");
    }
    return 0;
}