I - I'm Telling the Truth

Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Submit ​​Status​​ ​​Practice​​ ​​UVALive 5033​



Description


UVALive 5033 	I

After this year's college-entrance exam, the teacher did a survey in his class on students' score. There are n students in the class. The students didn't want to tell their teacher their exact score; they only told their teacher their rank in the province (in the form of intervals).

After asking all the students, the teacher found that some students didn't tell the truth. For example, Student1 said he was between 5004-th and 5005-th, Student2 said he was between 5005-th and 5006-th, Student3 said he was between 5004-th and 5006-th, Student4 said he was between 5004-th and 5006-th, too. This situation is obviously impossible. So at least one told a lie. Because the teacher thinks most of his students are honest, he wants to know how many students told the truth at most.



Input



There is an integer in the first line, represents the number of cases (at most 100 cases). In the first line of every case, an integer n(n60) represents the number of students. In the next n lines of every case, there are 2 numbers in each line, Xi and Yi(1XiYi100000), means the i-th student's rank is between Xi and Yi, inclusive.



Output



Output 2 lines for every case. Output a single number in the first line, which means the number of students who told the truth at most. In the second line, output the students who tell the truth, separated by a space. Please note that there are no spaces at the head or tail of each line. If there are more than one way, output the list with maximum lexicographic. (In the example above, 1 2 3;1 2 4;1 3 4;2 3 4 are all OK, and 2 3 4 with maximum lexicographic)



Sample Input



2 
4
5004 5005
5005 5006
5004 5006
5004 5006
7
4 5
2 3
1 2
2 2
4 4
2 3
3 4


Sample Output

3 
2 3 4
5
1 3 5 6 7


好爽!

我在百度搜索hdu 二分图最大匹配,百度给出的第一个结果就是这道题。刚开始看这道题的时候,以我对二分图匹配非常浅薄的理解,我怎么也想不明白这道题怎么就二分图最大匹配了。

后来想明白了,对于第i个人,我们知道他的合法区间[a[i].x,a[i].y]。首先我们将其和他合法区间内的第一个值进行匹配,如果有后来的 人需要和这个值匹配的时候,我们就让这个人和别的合法区间内的值进行匹配,如果匹配成功,就将他之前所匹配的值让出来给后来的人,如果匹配失败,就继续占 着这个位置。

这里很重要的一点是,对于一个值的匹配,我们遵守先来后到的原则,对于先来的已经匹配成功的人,如果没有找到其他符合条件的位置,这个人占的位置是绝对不能让出来的。这点很关键,因为题目还要求输出所有可能性中字典序最大的。

感觉做完这道题对二分图最大匹配理解深刻了好多,之前就是看懂了模板而已。而且还是1A。爽!



#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100005;
const int INF = 1000000000;
bool vis[maxn]; //查询右集合中的点有没有被访问过
int link[maxn]; //link[i]表示右集合中的i点是由左集合中的哪个点连接的
int G[100][maxn]; //邻接矩阵
int x_cnt;
int y_cnt; //左右集合的点的个数
int a[300];
int tmin,tmax;
bool find(int u) //用来寻找增广路

{
for(int i = tmin; i <= tmax; i++) //遍历右集合中的每个点
{
if(!vis[i] && G[u][i]) //没有被访问过并且和u点有边相连
{
vis[i] = true; //标记该点
if(link[i] == -1 || find(link[i]))
{
//该点是增广路的末端或者是通过这个点可以找到一条增广路
link[i] = u;//更新增广路 奇偶倒置
return true;//表示找到一条增广路
}
}
}
return false;//如果查找了右集合里的所有点还没找到通过该点出发的增广路,该点变不存在增广路
}

int solve()
{
int num = 0;
memset(link, -1, sizeof(link));//初始化为-1表示 不与左集合中的任何元素有link
for(int i =x_cnt ; i >=1; i--) //遍历左集合
{
memset(vis, false, sizeof(vis));//每一次都需要清除标记
if(find(i))
num++;//找到一条增广路便num++
}
return num;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
tmin=10000000,tmax=-1;
int u,v;
x_cnt=n;
memset(G,0,sizeof(G));
for(int i=1;i<=n;i++){
scanf("%d%d",&u,&v);
if(u<tmin)
tmin=u;
if(v>tmax){
tmax=v;
}
for(int j=u;j<=v;j++)
G[i][j]=1;
}
int cnt=0;
int ans=solve();
printf("%d\n",ans);
memset(a,0,sizeof(a));
for(int i=tmin;i<=tmax;i++){
if(link[i]!=-1)
a[cnt++]=link[i];
}
sort(a,a+cnt);

for(int i=0;i<cnt;i++){
printf("%d%c",a[i],i==cnt-1?'\n':' ');
}


}
return 0;
}