题目传送门
Sample Input
2
4
3
3 4
1 3
2 3
3
3
1 3
1 2
2 3
Sample Output
2
1
题目描述:城镇里的街道从一个交叉口连接到另一个交叉口,街道都是单向的,并且从一个交叉口沿着街道出发不会回到相同的交叉口。伞兵降临在城镇的一个交叉口并可以沿着街道走向另一个没有被其他伞兵走过的交叉口,问城镇中的所有交叉口都被伞兵走过的情况下至少需要多少伞兵。
最小不相交路径覆盖,拆点用二分图求。 最小不相交路径覆盖=点的总数-最大匹配
HK 和 匈牙利算法 都贴一下,以后当模板用。
HK真他妈长,还不如dinic。
//-----匈牙利-------
#include <cstdio>
#include <queue>
const int N=120+5;
const int M=120+5;
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
int mt[N],head[N];
bool vis[N];
int tot;
struct Edge{int to,nex;}edge[M];
bool dfs(int x)
{
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to;
if(!vis[y])
{
vis[y]=1;
if(!mt[y]||dfs(mt[y]))
{
mt[y]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int T;
scanf("%d",&T);
int n,m;
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
head[i]=0,mt[i]=0;
tot=1;
int a,b;
while(m--)
{
scanf("%d%d",&a,&b);
edge[++tot]=(Edge){b,head[a]};head[a]=tot;
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int i=1;i<=n;i++)
vis[i]=0;
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
}
//-------HK--------
#include <cstdio>
#include <queue>
const int N=1000+5;
const int M=12000+5;
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
struct Edge{int to,nex;}edge[M];
int mt[2*N],d[2*N],head[N];
int tot,n,m,dis;
bool vis[N];
queue<int>q;
bool searchP()
{
while(!q.empty())
q.pop();
for(int i=1;i<=2*n;i++)
d[i]=0;
dis=INF;
for(int i=1;i<=n;i++)
if(!mt[i])
q.push(i);
while(!q.empty())
{
int x=q.front();
q.pop();
if(d[x]>dis)
break;
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to;
if(!d[y])
{
d[y]=d[x]+1;
if(!mt[y])
dis=d[y];
else
{
d[mt[y]]=d[y]+1;
q.push(mt[y]);
}
}
}
}
return dis!=INF;
}
bool dfs(int x)
{
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to;
if(!vis[y]&&d[y]==d[x]+1)
{
vis[y]=1;
if(mt[y]&&d[y]==dis)
continue;
if(!mt[y]||dfs(mt[y]))
{
mt[x]=y;
mt[y]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
for(int i=1;i<=n;i++)
head[i]=0;
tot=1;
scanf("%d%d",&n,&m);
int a,b;
while(m--)
{
scanf("%d%d",&a,&b);
edge[++tot]=(Edge){b+n,head[a]};head[a]=tot;
}
int ans=0;
for(int i=1;i<=2*n;i++)
mt[i]=0;
while(searchP())
{
for(int i=1;i<=n;i++)
vis[i+n]=0;
for(int i=1;i<=n;i++)
if(!mt[i]&&dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
}