题意:
有N个甜点,和M头牛。每头牛对应有两种喜欢的食物,当牛能够吃到自己喜欢的食物,就会开心,否则不开心。同时每只牛去吃甜点时,会把他喜欢的都吃掉,即只要剩下他喜欢的,他都会吃掉。
现在问至少有多少牛会伤心。
思路:
如果读题不仔细,或许就会往 二分图匹配,网络流这些地方去想(因为都可以解决匹配问题)。但是这里有些不同,即是 一头牛可能会吃多个(多匹配)。不过往图的方向思考的确是正确的。
由于每只动物都有两个最喜欢的零食,这暗示我们应该将问题建模为图。 节点是小吃,边是动物与其喜欢的甜点(动物没有结点)。
让我们考虑一个大小大于1的图的连通分量
吃该组分的第一个动物(边)必须吃两个零食(节点),所有其他零食节点将被一个动物吃掉(边连接)。 总是可以找到一个订单,这样其他动物就不会吃两个零食(例如,BFS序列)。 因此,具有c个顶点的连通分量最多可以满足c-1动物。
N为小吃的数量,M是动物的数量,C是连接组件的数量(包括大小为1的组件)。 满意动物的数量是N-C,因此不快乐动物的数量是M-(N-C)。
所以这个图论模型关键在于 ,把动物抽象成边,甜点抽象成结点。吃,即意味着将结点进行连接,最后最多有多少条边能够连接完这些点
code:
#include <bits/stdc++.h> const int maxn = 1e5+7; const int maxm = 1e6+7; const int mod = 1e9+7; int pre[maxn]; int sz[maxn]; int find(int x){ return pre[x]==x?pre[x]:find(pre[x]); } void unite(int x, int y) { int px = find(x), py = find(y); if (px == py) return ; else if (sz[px] > sz[py]) { pre[py] = px; } else { pre[px] = py; if (sz[px] == sz[py]) sz[py]++; } } bool same(int x, int y) { int px = find(x), py = find(y); return px == py; } void init(int n){ for(int i=0;i<=n;i++){ pre[i]= i; sz[i] =1; } } int main(){ int n,m; cin>>n>>m; init(n); int cnt = 0; for(int i=0;i<m;i++){ int u,v; cin>>u>>v; if(!same(u,v)){ unite(u,v); cnt++; } } cout<<m-cnt<<endl; return 0; }