第十五届四川省省赛 SCU - 4443 Range Query

先给你1~N的N个数 再给你每种最多50个的条件(ai,bi,ci) 或者[ai,bi,ci]

(ai,bi,ci)表示下标ai到bi的最小值必为ci [ai,bi,ci]表示下标ai到bi的最大值必为ci

问你能不能有一种1~N的排列满足要求且字典序最小

首先这是一个左边n个 右边n个的二分图 左边表示位置 右边表示值

每个位置只能对应一个值 且要完美匹配才有解

那么如何建边?

我们用l[i] r[i]两个数组表示值i必定出现的最右左界和最左右界

用minn[i] maxn[i]两个数组表示下标i这个位置所有条件里面的最大最小值和最小最大值

这样可以使得连的边数最少.

然后check匹配数是否为N

在完美匹配有解的前提下完成最小字典序

从1~N暴力依次尝试匹配比linkx小的值

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 55;
const int N = 55;
int l[MAXN], r[MAXN];
int minn[MAXN], maxn[MAXN];
int n;
int useif[N];   //记录y中节点是否使用 0表示没有访问过,1为访问过
int linky[N];   //记录当前与y节点相连的x的节点
int linkx[N];
int mat[N][N]; //记录连接x和y的边,如果i和j之间有边则为1,否则为0
int gn, gm;   //二分图中x和y中点的数目
int can(int t)
{
    int i;
    for (i = 1; i <= gm; i++) {
        if (useif[i] == 0 && mat[t][i]) {
            useif[i] = 1;
            if (linky[i] == -1 || can(linky[i])) {
                linky[i] = t;
                linkx[t] = i;
                return 1;
            }
        }
    }
    return 0;
}
int MaxMatch()
{
    int i, num;
    num = 0;
    memset(linky, -1, sizeof(linky));
    memset(linkx, -1, sizeof(linkx));
    for (i = 1; i <= gn; i++) {
        memset(useif, 0, sizeof(useif));
        if (can(i)) {
            num++;
        }
    }
    return num;
}
void init()
{
    memset(mat, 0, sizeof(mat));
    for (int i = 1; i <= n; i++) {
        minn[i] = l[i] = 1, maxn[i] = r[i] = n;
    }
}
int main()
{
    int m1, m2;
    while (scanf("%d %d %d", &n, &m1, &m2) != -1) {
        init();
        int u, v, c;
        gn = gm = n;
        for (int i = 1; i <= m1; i++) {
            scanf("%d %d %d", &u, &v, &c);
            for (int j = u; j <= v; j++) {
                minn[j] = max(minn[j], c);
            }
            l[c] = max(l[c], u);
            r[c] = min(r[c], v);
        }
        for (int i = 1; i <= m2; i++) {
            scanf("%d %d %d", &u, &v, &c);
            for (int j = u; j <= v; j++) {
                maxn[j] = min(maxn[j], c);
            }
            l[c] = max(l[c], u);
            r[c] = min(r[c], v);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = minn[i]; j <= maxn[i]; j++) {
                if (l[j] <= i && i <= r[j]) {
                    mat[i][j] = 1;
                }
            }
        }
        int ans = MaxMatch();
        if (ans != n) {
            printf("-1\n");
        } else {
            for (int i = 1; i <= n; i++) {
                int now = linkx[i];
                mat[i][now] = 0;
                linky[now] = -1;
                bool flag = 0;
                memset(useif, 0, sizeof(useif));
                for (int j = 1; j < now; j++) {
                    if (useif[j] == 0 && mat[i][j]) {
                        useif[j] = 1;
                        if (linky[j] == -1 || can(linky[j])) {
                            linky[j] = i;
                            linkx[i] = j;
                            flag = 1;
                            break;
                        }
                    }
                }
                if (!flag) {
                    mat[i][now] = 1;
                    linky[now] = i;
                    linkx[i] = now;
                }
                now = linkx[i];
                for (int j = 1; j <= n; j++) {
                    mat[j][now] = 0;
                }
            }
            for (int i = 1; i <= n; i++) {
                printf("%d", linkx[i]);
                if (i != n) {
                    printf(" ");
                } else {
                    printf("\n");
                }
            }
        }
    }
}
View Code

 

posted @ 2018-11-06 19:09  Aragaki  阅读(247)  评论(0编辑  收藏  举报