题目大意:有n个学生,每个学生给一个区间,表示自己真实的rank范围,但是其中有一些人说谎了。求最大说真话的人数并字典序最大输出说真话的同学编号。
题目分析:不会证明的贪心注定是悲剧。。。
原来是个裸的二分匹配。因为要输出字典序最大,hk换了各种姿势都不太对,果然是多路增广的问题么。还是没有想通。
不过hungry很容易解决,因为hungry每次只找一条增广路,所以每次从x的大标号开始匹配,能够保证x尽量匹配上大编号的。所以能得出字典序最大。
详情请见代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 61;
const int M = 100005;
const int NM = 6000005;
const int inf = 0x3f3f3f3f;
int head[N];
struct node
{
int to,next;
}g[NM];
int n,m,num;
int matchx[N],matchy[M];
int que[M],ans[N],dis[N];
void build(int s,int e)
{
g[num].to = e;
g[num].next = head[s];
head[s] = num ++;
}
int path(int u)
{
int i,v;
for(i = head[u];~i;i = g[i].next)
{
v = g[i].to;
if(dis[v] == 0)
{
dis[v] = 1;
if(matchy[v] == -1 || path(matchy[v]))
{
matchx[u] = v;
matchy[v] = u;
return 1;
}
}
}
return 0;
}
void Hungry()
{
memset(matchx,-1,sizeof(matchx));
memset(matchy,-1,sizeof(matchy));
int i,maxmatch;
maxmatch = 0;
for(i = n;i >= 1;i --)
if(matchx[i] == -1)
{
memset(dis,0,sizeof(dis));
maxmatch += path(i);
}
printf("%d\n",maxmatch);
for(i = 1;i <= n;i ++)
if(matchx[i] > -1)
{
-- maxmatch;
printf("%d%c",i,maxmatch?' ':'\n');
}
}
int main()
{
int t,i,j;
int l,r;
scanf("%d",&t);
while(t --)
{
scanf("%d",&n);
memset(head,-1,sizeof(head));
num = 1;
for(i = 1;i <= n;i ++)
{
scanf("%d%d",&l,&r);
for(j = l;j <= r;j ++)
build(i,j);
}
Hungry();
}
return 0;
}