题目大意
给出一个折线图,有N条线段,你想要把这些线段分成几个集合,使得每个集合中任意两条线段不相交。
求最少集合数。
分析
喵帕斯:以下提及的所有折线均指横坐标在\([1,k]\)里的折线段。
思考两个折线若不相交会是什么情况?
对,即一个在上,一个在下(怎么有点奇怪呢)。
比如折线\(a\)在上,折线\(b\)在下,尝试对所有满足此关系的折线二元组连一条\(a\)到\(b\)的有向边,我们可以发现,使用一个集合可以走一条路径,那么题目求最小集合数,即求走最少的路径,师所有点全部被覆盖。
然后此题就转化为了最小路径覆盖问题,假设你已经会了该问题,然后就是喜闻乐见的匈牙利模板时间啦~
不会?
祝好梦。
#include<queue> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define ll long long const int N = 200 + 5; const int M = 10000 + 5; inline int read(){ int f = 1, x = 0; char ch; do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0' || ch > '9'); do {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } while (ch >= '0' && ch <= '9'); return f * x; } inline void write(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); } inline int max(int a, int b) { return a < b ? b : a; } inline int min(int a, int b) { return a < b ? a : b; } struct Graph { int to[M << 1], nxt[M << 1], head[N], cnt; inline void add(int x, int y) { ++cnt; to[cnt] = y, nxt[cnt] = head[x], head[x] = cnt; return; } }G; int t, n, k, price[N][30], op, tot; int vis[N], match[N], bj[N]; inline bool dfs(int u) { for (int i = G.head[u];i;i = G.nxt[i]) { int v = G.to[i]; if (!vis[v]) { vis[v] = 1; if (!match[v] || dfs(match[v])) { match[v] = u, bj[u] = v; return 1; } } } return 0; } int rate[N]; inline bool cmp(const int &x, const int &y) { return price[x][0] > price[y][0]; } inline bool can(int u, int v) { for (int i = 1;i <= k; ++i) { if (price[u][i] <= price[v][i]) return 0; } return 1; } int main(){ // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); t = read(); while (t --) { n = read(), k = read(); memset(bj, 0, sizeof bj); memset(G.head, 0, sizeof G.head); memset(match, 0, sizeof match); memset(price, 0, sizeof price); G.cnt = 0; for (int i = 1;i <= n; ++i) { for (int j = 1;j <= k; ++j) { price[i][j] = read(); price[i][0] = max(price[i][0], price[i][j]); } rate[i] = i; } std :: sort(rate + 1, rate + 1 + n, cmp); for (int i = 1, u;i <= n; ++i) { u = rate[i]; for (int j = i + 1, v;j <= n; ++j) { v = rate[j]; if (can(u, v)) G.add(u, v); } } tot = 0; for (int i = 1;i <= n; ++i) { if (bj[i] == 0) { memset(vis, 0, sizeof vis); if (dfs(i)) tot ++; } } printf("Case #%d: %d\n", ++op, n - tot); } return 0; }