12549 - Sentry Robots (二分图匹配)

来源:互联网 发布:新淘宝店如何破零知乎 编辑:程序博客网 时间:2024/05/17 04:32

该题和HDU 5093 如出一辙 传送门  。即求解二分图最大匹配数 = 最小点集覆盖 。 该题要求用尽量少的机器人看守所有重要的点,并且障碍物会阻隔机器人的看守范围  。

我们不妨将行列分开,按照行和列的最大看守范围编号,这样得到的就是最大匹配数 。 由于要求看守所有重要的点,所以这样可以有效去重,进行了最大匹配之后还可以保证一定看守了所有的点 。 建好图之后套Dinic模板就行了 。

该题有点逆着来的意思 ,请读者仔细品味 。

细节参见代码:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int INF = 1000000000;const int maxn = 20000 + 100;int T,cnt,n,m,u,pp,a,b,v,w,t,id1[100][100],id2[100][100];char s[maxn][maxn];struct Edge {  int from, to, cap, flow;};bool operator < (const Edge& a, const Edge& b) {  return a.from < b.from || (a.from == b.from && a.to < b.to);}struct Dinic {  int n, m, s, t;  vector<Edge> old;  vector<Edge> edges;    // 边数的两倍  vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号  bool vis[maxn];        // BFS使用  int d[maxn];           // 从起点到i的距离  int cur[maxn];         // 当前弧指针void init(int n) {    for(int i = 0; i < n; i++) G[i].clear();    edges.clear();}void AddEdge(int from, int to, int cap) {    edges.push_back((Edge){from, to, cap, 0});    edges.push_back((Edge){to, from, 0, 0});    m = edges.size();    G[from].push_back(m-2);    G[to].push_back(m-1);}bool BFS() {    memset(vis, 0, sizeof(vis));    queue<int> Q;    Q.push(s);    vis[s] = 1;    d[s] = 0;    while(!Q.empty()) {      int x = Q.front(); Q.pop();      for(int i = 0; i < G[x].size(); i++) {        Edge& e = edges[G[x][i]];        if(!vis[e.to] && e.cap > e.flow) {          vis[e.to] = 1;          d[e.to] = d[x] + 1;          Q.push(e.to);        }      }    }    return vis[t];}int DFS(int x, int a) {    if(x == t || a == 0) return a;    int flow = 0, f;    for(int& i = cur[x]; i < G[x].size(); i++) {      Edge& e = edges[G[x][i]];      if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {        e.flow += f;        edges[G[x][i]^1].flow -= f;        flow += f;        a -= f;        if(a == 0) break;      }    }    return flow;}int Maxflow(int s, int t) {    this->s = s; this->t = t;    int flow = 0;    while(BFS()) {      memset(cur, 0, sizeof(cur));      flow += DFS(s, INF);    }    return flow;  }}g;char ss[maxn][maxn];map<int,int> p;int main() {    scanf("%d",&T);    while(T--) {        scanf("%d%d%d",&n,&m,&pp);        for(int i=1;i<=n;i++)            for(int j=1;j<=m;j++) s[i][j] = '.';        g.init(n*m*2+n);        for(int i=1;i<=pp;i++) {            scanf("%d%d",&a,&b);            s[a][b] = '*';        }        scanf("%d",&w);        for(int i=1;i<=w;i++) {            scanf("%d%d",&a,&b);            s[a][b] = '#';        }        int cnt = 1;        for(int i=1;i<=n;i++) {            for(int j=1;j<=m;j++) {                if(s[i][j] == '#') cnt++;//按照行编号                if(s[i][j] == '*') id1[i][j] = cnt;            }            cnt++;        }        for(int j=1;j<=m;j++) {            for(int i=1;i<=n;i++) {                if(s[i][j] == '#') cnt++;//按列编号                if(s[i][j] == '*') id2[i][j] = cnt;            }            cnt++;        }        p.clear();        for(int i=1;i<=n;i++) {            for(int j=1;j<=m;j++) {                if(s[i][j] == '*') {                    g.AddEdge(id1[i][j],id2[i][j],1);//连边                    if(!p.count(id1[i][j])) { //每个编号只能与源点连一次                        p[id1[i][j]] = 1;                        g.AddEdge(0,id1[i][j],1);                    }                    if(!p.count(id2[i][j])) {//同上                        p[id2[i][j]] = 1;                        g.AddEdge(id2[i][j],cnt+1,1);                    }                }            }        }        int ans = g.Maxflow(0,cnt+1);        printf("%d\n",ans);    }    return 0;}


1 1
原创粉丝点击