202400610刷題總結

琴忆庭發表於2024-06-10

T1

T559。

T2(帶權並查集)

1380。
把行和列的取值看成變數,其中行取1代表+1,列取1代表-1,為了湊x - y = c,這樣可以拿並查集來做了。
維護d[x],到根的距離,我們把邊定義為+,反向走為-。這樣就行了,如果在一個集合,那麼判斷距離是不是c。
還可以差分約束,dfs(直接遍歷一遍,遇到環就判斷).

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m, k;
int p[N << 1], d[N];

int find(int x)
{
    if (p[x] == x) return x;
    
    int fa = find(p[x]);
    d[x] += d[p[x]];
    return p[x] = fa;
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n + m; i ++ ) p[i] = i;
    while (k -- )
    {
        int x, y, c;
        scanf("%d%d%d", &x, &y, &c);
        y += n;
        int px = find(x), py = find(y);
        if (px != py)
        {
            p[py] = px;
            d[py] = d[x] + c - d[y];
        }
        else if (d[y] - d[x] != c)
        {
            puts("No");
            return 0;
        }
    }
    puts("Yes");
    return 0;
}

T3(帶權並查集,與上題類似)

換成乘。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 20010;

int p[N];
double d[N];
int n, m;

int find(int x)
{
    if (p[x] == x) return x;
    int fa = find(p[x]);
    d[x] *= d[p[x]];
    return p[x] = fa;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ ) p[i] = i, d[i] = 1;
    while (m -- )
    {
        int x, y, a, b;
        scanf("%d%d%d%d", &x, &y, &a, &b);
        int px = find(x), py = find(y);
        if (px != py)
        {
            p[py] = px;
            d[py] = d[x] * a / b / d[y]; 
        }
        else
        {
            if (abs(d[x] - (d[y] * b / a)) >= 1e-5)
            {
                puts("No");
                return 0;
            }
        }
    }
    puts("Yes");
    return 0;
}

T4(差分約束,不等式及相對關係->差分約束)

1129。 https://www.luogu.com.cn/problem/P2474
這個題首先要想到列舉,然而我們不知道他們之間的關係,無法判斷。求解相對關係,我們發現a+b = c+d 加法不好處理,這個等式實際上就是a - c = d - b,這樣就轉化為了求差值的範圍,其實就是差分約束。不等式是啥呢?根據給定的圖,a-b的關係就給了,floyd求差分約束就行了。最後暴力列舉判斷。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110;

int mind[N][N], maxd[N][N];
int n, A, B;
char g[N][N];

void floyd()
{
    for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
            {
                mind[i][j] = max(mind[i][j], mind[i][k] + mind[k][j]);
                maxd[i][j] = min(maxd[i][j], maxd[i][k] + maxd[k][j]);
            }
}

int main()
{
    freopen("balance.in", "r", stdin);
	freopen("balance.out", "w", stdout);
    scanf("%d%d%d", &n, &A, &B);
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%s", g[i] + 1);
        for (int j = 1; j <= n; j ++ )
            if (i != j)
            {
                if (g[i][j] == '+') mind[i][j] = 1, maxd[i][j] = 2;
                else if (g[i][j] == '?') mind[i][j] = -2, maxd[i][j] = 2;
                else if (g[i][j] == '-') mind[i][j] = -2, maxd[i][j] = -1;
            }
    }
    floyd();
    int c1 = 0, c2 = 0, c3 = 0;
    for (int i = 1; i <= n; i ++ )
        for (int j = i + 1; j <= n; j ++ )
            if (i != j && i != A && i != B && j != A && j != B)
            {
                if (mind[A][i] > maxd[j][B] || mind[A][j] > maxd[i][B]) c1 ++ ;
                if ((maxd[A][i] == mind[A][i] && maxd[j][B] == mind[j][B] && mind[A][i] == maxd[j][B])
                || (maxd[A][j] == mind[A][j] && maxd[i][B] == mind[i][B] && mind[A][j] == maxd[i][B]))
                    c2 ++ ;
                if (maxd[A][i] < mind[j][B] || maxd[A][j] < mind[i][B]) c3 ++ ;
            }
    
    printf("%d %d %d\n", c1, c2, c3);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

相關文章