先给你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小的值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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 "); } 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(" "); } } } } }