一个点集是学生,一个点集是排名。然后通过学生的排名范围连线,求此二分图的最大匹配。
本题还要求是最大字典序输出,那么由贪心可得,你让标号从大到小找增广边就行了。
#include <cstdlib> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <fstream> #include <iostream> #define rep(i, l, r) for(int i=l; i<=r; i++) #define down(i, l, r) for(int i=l; i>=r; i--) #define N 69 #define M 100009 using namespace std; int read() { int x=0, f=1; char ch=getchar(); while (ch<'0' || ch>'9') { if (ch=='-') f=-1; ch=getchar(); } while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } int n, l[N], r[N], k[M], b[M], ans, ansk[N], s; bool Find(int x) { rep(i, l[x], r[x]) if (b[i]!=s) { b[i]=s; if (!k[i] || Find(k[i])) { k[i]=x; return true; } } return false; } int main() { int t=read(); while (t--) { n=read(); rep(i, 1, n) l[i]=read(), r[i]=read(); rep(i, 1, M-1) k[i]=b[i]=0; rep(i, 1, n) ansk[i]=0; ans=0; down(i, n, 1) if (Find(s=i)) ans++, ansk[i]=1; printf("%d ", ans); rep(i, 1, n) if (ansk[i]) { if (--ans) printf("%d ", i); else printf("%d ", i); } } return 0; }