https://blog.youkuaiyun.com/mengxiang000000/article/details/50445025# 匈牙利算法讲解
HDU-3729
题意:有一些学生,自己说出了一个名次的起点与终点,输出最多有多少人在说真话,并输出字典序最大的学生编号序列
思路:二分图求最大权匹配,注意从编号最大的学生开始匹配。一般用vector版本的匈牙利算法。
每次调用匈牙利算法前一定要清空vis数组。
vector里面保存的是g[i][j]表示第i个学生可以与第j个名次匹配。match[i]保存的第i个名次的匹配结果。
注意调用的dfs参数i不能是0 因为要用!match[i]判断是否已经匹配过 如果dfs(0) 可能误以为match[i]还没有匹配过
#include <bits/stdc++.h>
// 最多有60个学生,1e5个名次
using namespace std;
vector <int> g[80];//学生存储名次
int vis[100005];//访问标记
int match[100005];//匹配标记
int n;
bool dfs(int x)
{
int len=g[x].size();
for(int i=0; i<len; i++)
{
int t=g[x][i];
if(!vis[t])//这个名次没有被访问过
{
vis[t]=1;
if(!match[t]||dfs(match[t]))//这个名次没有被匹配过 或者
{ //如果已经被匹配过,看能否让已经匹配这
//个名次的同学找另外一个没有被匹配的名次
match[t]=x;
return true;
}
}
}
return false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0; i<=n; i++)
{
g[i].clear();
}
memset(match,0,sizeof(match));
for(int i=1; i<=n; i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(a>b)
swap(a,b);
for(int j=a; j<=b; j++)
{
g[i].push_back(j);
}
}
vector <int> v;
int ans=0;
for(int i=n; i>=1; i--)
{
memset(vis,0,sizeof(vis));
if(dfs(i))//注意调用的参数i不能是0 因为要用!match[i]判断是否已经匹配过
{
ans++;
v.push_back(i);
}
}
sort(v.begin(),v.end());
printf("%d\n",ans);
for(int i=0; i<v.size(); i++)
{
if(i)
printf(" ");
printf("%d",v[i]);
}
printf("\n");
}
return 0;
}