POJ3041 Asteroids 二分图最小顶点覆盖 Dinic求解最大流

来源:互联网 发布:中国化妆品进出口数据 编辑:程序博客网 时间:2024/06/09 21:01

题意

  • 一个n*n的矩阵,有k个位置有小行星,一炮可以摧毁一行或一列行星
  • 问最少需要多少炮可以摧毁所有行星

思路

  • 把一行、一列看成节点,矩阵里的一个小行星看成一条边,如行星位置(r,c),则第r行的节点和第c列形成的节点间有一条边。
  • 然后我们的问题就变成了求解该图的最小顶点覆盖
  • 因为行和行的节点之间无边,列和列也一样,因此可以形成二分图,所以用最大流求解即可

实现

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cmath>#include <queue>#include <iostream>using namespace std;const int INF = 0x3f3f3f3f;//Dinic最大流, 节点编号从0开始 struct MaxFlow{    const static int MAX_V = 1005;    int V;    //终点、容量、反向边     struct edge{        int to, cap, rev;    };    vector<edge> G[MAX_V];    int level[MAX_V];//顶点到源点的距离标号     int iter[MAX_V];// 当前弧,在其之前的边已经没有用了    void add_edge(int from, int to, int cap){        G[from].push_back((edge){to, cap, (int)G[to].size()});        G[to].push_back((edge){from, 0, (int)G[from].size()-1});    }     // 通过BFS计算从源点出发的距离标号     void bfs(int s){        fill(level, level + V, -1);        queue<int> que;        level[s] = 0;        que.push(s);        while (!que.empty()){            int v = que.front();            que.pop();            for (int i=0; i< G[v].size(); i++){                edge& e = G[v][i];                if (e.cap > 0 && level[e.to] < 0){                    level[e.to] = level[v] + 1;                    que.push(e.to);                }            }        }    }    //通过DFS寻找增广路     int dfs(int v, int t, int f){        if (v == t)            return f;        for (int &i = iter[v]; i < G[v].size(); i++){            edge& e = G[v][i];            if (e.cap > 0 && level[v] < level[e.to]){                int d = dfs(e.to, t, min(f, e.cap));                if (d > 0){                    e.cap -= d;                    G[e.to][e.rev].cap += d;                    return d;                }            }        }        return 0;    }    //求解从s到t的最大流     int max_flow(int s, int t){        int flow = 0;        for (;;){            bfs(s);            if(level[t] < 0)                return flow;            fill(iter, iter + V, 0);            int f;            while ((f = dfs(s, t, INF)) > 0){                flow += f;            }        }    }    void init(int n = 0){        for (int i = 0; i < V; i++){            G[i].clear();        }        V = n;    }}mf;int n,m;int main(){    ios::sync_with_stdio(false);    cin>>n>>m;    mf.V = 2*n+2;    for (int i=1;i<=n;i++){        mf.add_edge(0, i, 1);        mf.add_edge(i+n,2*n+1,1);    }    for (int i=0;i<m;i++){        int r,c;        cin>>r>>c;        mf.add_edge(r,c+n,1);    }    cout << mf.max_flow(0,2*n+1) << endl;    return 0;}
0 0
原创粉丝点击