hdu1054 Strategic Game(最小顶点覆盖)

http://acm.hdu.edu.cn/showproblem.php?pid=1054题意:Bob想要保卫一个中世纪城市,每个节点可以放一个工兵,每个工兵只能从一条路的一端打向另一端,如果这个节点相连多个边,那么与之相连的点工兵都可以保卫到。所有的道路组成一颗树,求可以保卫这棵树所需要的最少工兵数是多少。ps:刚学了匈牙利算法,就是那个趣写教程,太火了就不上链接了。整体思
摘要由CSDN通过智能技术生成


http://acm.hdu.edu.cn/showproblem.php?pid=1054

题意:Bob想要保卫一个中世纪城市,每个节点可以放一个工兵,每个工兵只能从一条路的一端打向另一端,如果这个节点相连多个边,那么与之相连的点工兵都可以保卫到。所有的道路组成一颗树,求可以保卫这棵树所需要的最少工兵数是多少。


ps:刚学了匈牙利算法,就是那个趣写教程,太火了就不上链接了。整体思路就是遍历每个点,看这个节点是否可以找到对应的匹配。

每个点的匹配过程中,遍历该点所想匹配的所有点。如果在本次递归内没有访问过,那就对此点访问,若访问过则遍历下一个相匹配的点。

可以访问后,就查看自己想匹配点的状态,满足这两种状态的任意一种都可以找到匹配:

(1)、想匹配的点还是单身狗;

(2)、想匹配的点已经有原配,那就试着拆原配,让原配去找小三。而找小三的人又可能去拆别人原配,这是一个递归。不过只要有一个人找到了小三,那别人也找到了小三,原配成功被小三拐走,想匹配的点重新变成单身狗。(为毛感觉画风突变= =)

若本次匹配失败,则遍历下一个想匹配的点(总不能在一棵树上吊死吧,想追就去追)。

若全部匹配都失败,那恭喜你汪汪汪了。


思路:最小顶点覆盖。可以转化为二分匹配模型,二分图中最小顶点覆盖数=最大匹配。详细可以看看我的理解。由于是无向图那么实际上两边的节点就是一样的,最后求出二分匹配数除以2即可。


#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <stack>
#include <ctype.h>

using namespace std;

typedef long long LL;

const int N = 1505;
const int INF = 0x3f3f3f3f;

int head[N], match[N];
bool vis[N];//vis代表某节点允许匹配的节点中在本次递归中是否被访问过
int n, m, cnt;

struct Edge
{
    int to,next;
}edge[N*N];

void add(int u, int v)
{
    edge[cnt] = (struct Edge){v, head[u]};
    head[u] = cnt++;
    edge[cnt] = (struct Edge){u, head[v]};
    head[v] = cnt++;
}

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}

bool Augment(int n, int u)
{
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(!vis[v])
        {
            vis[v] = true;
            if(match[v]==-1 || Augment(n, match[v]))//单身狗或拆原配
            {
                match[v] = u;
                return true;
            }
        }
    }
    return false;
}

int Hungary(int n)
{
    int ans = 0;
    memset(match, -1, sizeof(match));
    for(int i = 0; i < n; i++)
    {
        memset(vis, false, sizeof(vis));
        if(Augment(n, i)) ans++;
    }
    return ans;
}

int main()
{
  //  freopen("in.txt", "r", stdin);
    int n, m, u, v;
    while(~scanf("%d", &n))
    {
        init();
        for(int i = 0; i < n; i++)
        {
            scanf("%d:(%d)", &u, &m);
            while(m--)
            {
                scanf("%d", &v);
                add(u, v);
            }
        }
        printf("%d\n", Hungary(n)/2);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值