来源:2010 Asia Tianjin Regional Contest
类型:二分图
将每个学生看做一个点,每个名次看做一个点,对于每个学生,向其名次段的所有名次连边
如,学生1的名次段为1~3,则有边1->1, 1->2, 1->3【左边的点和右边的点不是同一类型的点】
题目要求的就是二分图的最大匹配
要求输出字典序最大的一组点,倒叙找增广路即可,比如最大的字典序解为x1,x2...xm,当找到点x1时,得到最大匹配,无法再进行增广
// hdoj 3729 I'm Telling the Truth
// wa ac
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int n;
int maxlen;
int result[maxn];
int end[62];
bool Array[62][maxn];
bool state [maxn];
bool find(int a) {
int i;
for (i = 1; i <= maxlen; i++) {
if(i == 5003)
{
int s = 0;
}
if (Array[a][i] == true && !state[i]) {
state[i] = true;
if (result[i] == 0 || find(result[i])) {
result[i] = a;
return true;
}
}
}
return false;
}
void solve() {
int i, j, m, x, y;
scanf("%d", &m);
while(m--) {
memset(result, 0, sizeof(result));
memset(end, 0, sizeof(end));
memset(Array, false, sizeof(Array));
maxlen = -1;
scanf("%d", &n);
for(i = 0; i < n; ++i) {
scanf("%d %d", &x, &y);
maxlen = max(maxlen, y);
for(j = x; j <= y; ++j)
Array[i][j] = true;
}
int len = 0;
for(i = n - 1; i >= 0; --i) {
memset(state, false, sizeof(state));
if(find(i))
end[len++] = i + 1;
}
printf("%d\n", len);
for(i = len - 1; i >= 0; --i)
(i == len - 1) ? printf("%d", end[i]) : printf(" %d", end[i]);
printf("\n");
}
return;
}
int main() {
solve();
return 0;
}