盒子 | ||||||
| ||||||
Description | ||||||
Tang长老带着集训队旅游结束后回到了实验室,还带回了好多的纪念品,实验室放满了各种物品的盒子,Tang长老说大家要注意形象,遂要求大家把盒子收拾好。实验室本来地方就比较小,所以大家想尽量腾出点地方来,还好盒子都是立方体的,一些盒子可以装在另一些盒子内部,于是大家想知道如果把一些盒子装在另一些盒子内部的话最少可以保留多少盒子露在外面,而且需要注意的是,当一个大的盒子装入一个小的盒子的时候,大的盒子的容量就会变为小的盒子的体积,即不能有超过两个盒子并列放在一个盒子内部,但是允许层层嵌套着放。
| ||||||
Input | ||||||
Line 1: 盒子的总数 N(2 ≤ N ≤ 500),盒子的大小关系数 M。 Line 2...M+1:两个整数 A,B,表示盒子 A 可以放在盒子 B 内部。 | ||||||
Output | ||||||
Line 1: 一个整数,表示露在外面的盒子的最少个数。 | ||||||
Sample Input | ||||||
3 2 1 2 2 3 | ||||||
Sample Output | ||||||
1 | ||||||
Author | ||||||
wind |
题目给出这样的全序关系:盒子 A 可以放在盒子 B 内部。相反的,盒子B是不能放在盒子A内部的,这样的一个有向图问题,第一发我竟然直接敲的并查集。。。。。。一开始的时候这个题给人的第一印象真的是并查集搞,最后查询一共有多少条路径。年轻的小伙伴就这样年轻的敲了一发并查集,然后开开心心的wa。
这个题的正确思路是这样的:
既然我们有全序关系,这里图就一定会保证不成环,如果一定不会成环的话,假如样例:
1 2
2 3
我把1放在2里边之后,2是一定不会回头有放在1里边的情况的,所以我们大可不必要担心成环问题。
既然不会成环,那我们应该如何去做这个题呢?
我们这样来想这个问题,如果1能放在2盒子里边,我们不管2能否放在其他盒子里,我们就单单讨论1和2的问题,这样我们就可以把12嵌套,变成一个盒子,这样我们就从3个盒子变成了两个盒子,我们再看2,2能放在3里边,同理就变成了一个盒子。那么我们如何实现这个问题呢、
二分匹配即可,贪心的去做,如果当前盒子能够放在其他盒子里边,我们就放在里边,当然如果盒子1可以放在盒子2,盒子2也可以放在盒子3,那么我们理应算作盒子1放在盒子3里边。
所以最终思路我们就可以相当于这样:
二分匹配匹配到一个,就相当于从n个盒子变成了n-1个盒子,如果继续向下匹配还能匹配到那么就从n-1个盒子变成了n-2个盒子。
AC代码:
#include<stdio.h>
#include<string.h>
using namespace std;
int match[505];
int vis[505];
int map[505][505];
int n,m;
int find(int x)
{
for(int i=1;i<=n;i++)
{
if(vis[i]==0&&map[x][i])
{
vis[i]=1;
if(match[i]==-1||find(match[i]))
{
match[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(match,-1,sizeof(match));
memset(map,0,sizeof(map));
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
map[x][y]=1;
}
int sum=0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(find(i))sum++;
}
printf("%d\n",n-sum);
}
}