POJ 3041 Asteroids (对偶性,二分图匹配)

题目:POJ 3041 Asteroids http://poj.org/problem?id=3041

分析

把位置下标看出一条边,这显然是一个二分图最小顶点覆盖的问题,Hungary就好。

挑战

输出一组可行解。构造,已知二分图的两个点集U和V,s-U-V-t,在最大匹配的残留网络里,选从s出发能到达的V中的点

沿途可以到达的U集中的点的路径就都被覆盖了,然后在选择U集合中无法到达的点。对于二分图中任意一条边,其中必有一点属于U集合,

所以前面选出的点集S是一个覆盖。并且S中V和U对应的匹配边是相斥的,总数确实等于总匹配边数。(更具体的,可以想想U是怎么划分的。)

如果最大匹配数记为M,最小点覆盖记为C。那么的构造还可以说明M≥C。又因为匹配边是平行的,所以至少要M个点才能覆盖,C≥M。这样

就得出了M = C的结论。

Code

/*********************************************************
*            ------------------                          *
*   author AbyssalFish                                   *
**********************************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
using namespace std;

typedef long long ll;

const int maxn = 501, maxm = 1e4+1;
int hd[maxn],to[maxm],nx[maxm],ec;
#define eachEage int i = hd[u]; i; i = nx[i]
void add(int u,int v)
{
    nx[++ec] = hd[u];
    to[ec] = v;
    hd[u] = ec;
}

int link[maxn];
int vis[maxn], clk;

bool dfs(int u)
{
    vis[u] = clk;
    for(eachEage){
        int v = to[i], w = link[v];
        if(!w || (vis[w]!=clk && dfs(w))){
            link[v] = u;
            return true;
        }
    }
    return false;
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    int n,k; scanf("%d%d",&n,&k);
    for(int i = 0; i < k; i++){
        int r, c;
        scanf("%d%d",&r,&c);
        add(r,c);
    }
    int ans = 0;
    for(int i = 1; i <= n; i++){
        clk++;
        if(dfs(i)) ans++;
    }
    printf("%d\n", ans);
    return 0;
}

 

posted @ 2015-11-08 15:58  陈瑞宇  阅读(291)  评论(0编辑  收藏  举报