Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=3729
【前言】
昨天做一份四道题的练习。
是去年天津区域赛的题目。
出了两道,不过觉得那两道都是比较简单的。
一道trie,一道暴力搜索。
剩下两道没好的思路。
后来查了一下,发现这道题是二分图匹配= =
另一道是KM。
这两个都不是我的范畴,所以不太熟悉。
好吧,今天过来学习了。
【思路】
发现之前用网络流做二分图匹配的那种方法不是很好。
匈牙利算法倒是个不错的选择。
(1)建图
从每个顶点(学生)到他所在的分数区间的每一个点做一个连线,从而形成一个二分图。
(2)匹配
运用匈牙利算法,对每一个顶点进行递归查找,直到结束。
由于要输出字典序最大的结果,所以查找的时候从后往前查找即可。
递归的效率还是比较低的,不过还是可以通过。
【代码】
参考网址:http://baike.baidu.com/view/501081.htm
#include <iostream>
using namespace std;
const int maxn = 60;
const int maxm = 100000;
bool g[maxn+5][maxm+5];//g[x][y]表示x、y两个点之间有边相连
bool y[maxm+5];//y记录的是y中的i节点是否被访问过
int link[maxm+5];//link[y]记录的是当前与y节点相连的x节点
bool find(int v, int m)
{
int i;
for(i=1;i<=m;i++)
{
if(g[v][i] && !y[i])
{
y[i]=true;
if(link[i]==0 || find(link[i],m))
{
link[i]=v;
return true;
}
}
}
return false;
}
int main()
{
int t;
int n, m;
int i, j;
int a, b;
int ans[maxn+5];
int ct;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
memset(g, false, sizeof(g));
memset(link, 0, sizeof(link));
m = -1;
for (i=1; i<=n; i++)//建图
{
scanf("%d %d", &a, &b);
for (j=a; j<=b; j++)
{
g[i][j] = true;
}
if (b>m) m=b;
}
ct = 0;
for(i=n; i>=1 ;i--)//匹配
{
for (j=0; j<=m; j++)
y[j] = false;
if(find(i, m))
{
ans[ct] = i;
ct++;
}
}
printf("%d\n", ct);
for (i=ct-1; i>=0; i--)//输出
{
if (i==ct-1) printf("%d", ans[i]);
else printf(" %d", ans[i]);
}
printf("\n");
}
return 0;
}