hdu1151Air Raid poj2594Treasure Exploration题解

Air Raid
题目的意思就是给一个有向无环图,求从最少的点出发,不能重复的走完所有点。其实就是有向无环图的最小路径覆盖。
有向无环图的最小路径覆盖=节点数-匹配数(拆点)

//建图,有向无环图的最小路径覆盖=节点数-匹配数(拆点)
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;

const int MAXN=123;
bool g[MAXN][MAXN],used[MAXN];
int linker[MAXN];
bool dfs(int u,int n)
{
    for(int v=1;v<=n;v++)
        if(g[u][v]&&!used[v]){
            used[v]=true;
            if(linker[v]==-1||dfs(linker[v],n)){
                linker[v]=u;
                return true;
            }
        }
    return false;
}
int hungary(int n)
{
    int res=0;
    msc(linker);
    for(int u=1;u<=n;u++)
    {
        ms(used);
        if(dfs(u,n)) res++;
    }
    return res;
}
int main(int argc, char const *argv[])
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        ms(g);
        while(m--){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u][v]=true;
        }
        printf("%d\n",n-hungary(n) );
    }
    return 0;
}
/*
2
11
10
1 2
2 3
3 6
6 11
11 7
11 8
11 9
5 10
10 4
4 6
3
3
1 2
1 3
2 3
*/

Treasure Exploration
题目的意思就是给一个有向无环图,求从最少的点出发,走完(可重复)所有点。
和上面的题有所改变,只需把x的可达点也加到x到该点的边就可以了。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;

const int MAXN=510;
bool g[MAXN][MAXN];
int linker[MAXN];
bool used[MAXN];
bool dfs(int u,int n)
{
    for(int v=1;v<=n;v++)
        if(g[u][v]&&!used[v]){
            used[v]=true;
            if(linker[v]==-1||dfs(linker[v],n)){
                linker[v]=u;
                return true;
            }
        }
    return false;
}
int hungary(int n)
{
    int res=0;
    msc(linker);
    for(int u=1;u<=n;u++)
    {
        ms(used);
        if(dfs(u,n)) res++;
    }
    return res;
}
int main(int argc, char const *argv[])
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2&&(n||m)){
        ms(g);
        while(m--){
            int a,b;
            scanf("%d%d",&a,&b);
            g[a][b]=true;
        }
        for(int k=1;k<=n;k++)
            for(int u=1;u<=n;u++)
                for(int v=1;v<=n;v++)
                    if(g[u][k]&&g[k][v])
                        g[u][v]=true;
        printf("%d\n",n-hungary(n) );
    }
    return 0;
}
/*
7 6
1 2
2 3
3 5
3 6
3 7
4 2

13 14
1 2
2 4
4 7
7 9
9 10
10 11
10 12
10 13
10 6
3 2
2 5
5 8
8 9
6 12

13 14
1 2
2 4
4 7
7 9
9 10
10 11
10 6
10 13
10 12
3 2
2 5
5 8
8 9
6 12
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值