杭电 hdu 1151 Air Raid (二分匹配 + 最小路径覆盖)

杭电   hdu  1151   Air Raid  (二分匹配 + 最小路径覆盖)




Air Raid

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3822    Accepted Submission(s): 2521


Problem Description
Consider a town where all the streets are one-way and each street leads from one intersection to another. It is also known that starting from an intersection and walking through town's streets you can never reach the same intersection i.e. the town's streets form no cycles.

With these assumptions your task is to write a program that finds the minimum number of paratroopers that can descend on the town and visit all the intersections of this town in such a way that more than one paratrooper visits no intersection. Each paratrooper lands at an intersection and can visit other intersections following the town streets. There are no restrictions about the starting intersection for each paratrooper.
 

Input
Your program should read sets of data. The first line of the input file contains the number of the data sets. Each data set specifies the structure of a town and has the format:

no_of_intersections
no_of_streets
S1 E1
S2 E2
......
Sno_of_streets Eno_of_streets

The first line of each data set contains a positive integer no_of_intersections (greater than 0 and less or equal to 120), which is the number of intersections in the town. The second line contains a positive integer no_of_streets, which is the number of streets in the town. The next no_of_streets lines, one for each street in the town, are randomly ordered and represent the town's streets. The line corresponding to street k (k <= no_of_streets) consists of two positive integers, separated by one blank: Sk (1 <= Sk <= no_of_intersections) - the number of the intersection that is the start of the street, and Ek (1 <= Ek <= no_of_intersections) - the number of the intersection that is the end of the street. Intersections are represented by integers from 1 to no_of_intersections.

There are no blank lines between consecutive sets of data. Input data are correct.
 

Output
The result of the program is on standard output. For each input data set the program prints on a single line, starting from the beginning of the line, one integer: the minimum number of paratroopers required to visit all the intersections in the town.
 

Sample Input
  
  
2 4 3 3 4 1 3 2 3 3 3 1 3 1 2 2 3
 

Sample Output
  
  
2 1
 

Source
 

Recommend
Ignatius.L   |   We have carefully selected several similar problems for you:   1281  1528  1498  1054  1533 
 









题意:这里有很多的村庄,会告诉你一些路,每一条路连接两个村庄,然后有很多的伞兵,要搜索所有的村庄,他们可以降落在指定的村庄。
没有连通路,也就是隔绝的村庄,只能靠伞兵的降落,而落地的伞兵不能去隔绝的村庄,要考新的伞兵,
问要搜查所有的村庄最少要多少的伞兵
首先输入T表示有多少测试案例
接着是n,表示有多少个村庄
然后是m,表示有多少条路
下面是m行,分别a,b,表示两个连通的村庄




题解:这是一道经典的最少路径覆盖,就是一条边,就是会花费一个人,要是一条新的边,就又要加一个新的人,要是是连续的一条边,那么就减去
一个去的人,最后就是总共有的村庄数,减去最大匹配数。






#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>

using namespace std;

int n, m;
bool map[1000][1000];              //记录村庄之间是否有路连通,0为不连通,1为连通
bool vis[10000];
int pri[10000];                      //用来记录最后pri[i] = x,i最后选择x

bool find (int x)
{
    int i;

    for (i = 1; i <= n; i++)
    {
        if (map[x][i] && !vis[i])             //保证两个点是连通的,并且,有没有被后来来的给看中,要是看中,就进行选中者判断,是否还有其他可以选择的选项
        {
            vis[i] = true;
            if (pri[i] == -1 || find(pri[i]))    //这就是判断前者是否可以将这个选中让给后者
            {
                pri[i] = x;
                return true;
            }
        }
    }
    return false;
}

int main ()
{
    int T, i, a, b;

    scanf ("%d", &T);
    while (T--)
    {
        scanf ("%d%d", &n, &m);
        memset (map, false , sizeof (map));
        memset (pri, -1, sizeof (pri));
        for (i = 1; i <= m; i++)
        {
            scanf ("%d%d", &a, &b);
            map[a][b] = true;                //标记村庄之间的联系
        }
        int ans = 0;
        for (i = 1; i <= n; i++)
        {
            memset (vis, false, sizeof (vis));
            if (find (i))
                ans++;
        }
        printf ("%d\n", n - ans);
    }

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值