CF-1209D Cow and Snacks (并查集,图)

原题链接:

题意:

有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;
} 

 

posted @ 2019-09-15 16:05  Tianwell  阅读(530)  评论(0编辑  收藏  举报