POJ1422:Air Raid——题解

http://poj.org/problem?id=1422

题目大意:n个点m条有向边,每条边只能走一次,往点上放人让他们走遍所有边,问至少要多少人。

——————————————————————

网上的题解都蛮详尽的了所以不想写这篇博客。

(但是强迫症)

首先这是一道最小路径覆盖问题,有结论转换成求|节点数-最大匹配|,证明看这个人的博客

我们将每个点拆分成两个点(设左点和右点),左点为一个集合,右点为一个集合。

这样的话两个点ij中间的有向边就是i左点连j右点。

#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
const int maxn=1001;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int n,m,e;
bool vis[maxn],a[maxn][maxn]={0};
int shu[maxn]={0};
bool dfs(int i){
    for(int j=1;j<=m;j++){
        if(a[i][j]&&!vis[j]){
            vis[j]=1;
            if(!shu[j]||dfs(shu[j])){
                shu[j]=i;
                return 1;
            }
        }
    }
    return 0;
}
int main(){
    int t=read();
    while(t--){
    memset(a,0,sizeof(a));
    memset(shu,0,sizeof(shu));
    int ans=0;
    m=n=read();
    e=read();
    for(int i=1;i<=e;i++){
        int u=read();
        int v=read();
        if(u>n||v>m) continue;
        a[u][v]=1;
    }
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(dfs(i))ans++;
    }
    printf("%d\n",n-ans);
    }
    return 0;
}

 

posted @ 2017-12-09 13:23  luyouqi233  阅读(209)  评论(0编辑  收藏  举报