UVA 12549 - 二分图匹配

题意:给定一个Y行X列的网格,网格种有重要位置和障碍物。要求用最少的机器人看守所有重要的位置,每个机器人放在一个格子里,面朝上下左右四个方向之一发出激光直到射到障碍物为止,沿途都是看守范围。机器人不会阻挡射线。

“#”表示障碍物,“*”表示重要的位置,箭头表示最终机器人匹配的位置,求出机器人能够匹配出的最少位置个数。

分析:首先看题解是二分图匹配,但是建图目前还没想到呢。每个机器人绝对都在重要位置上,假设每个重要位置上都有机器人,可以保护哪几个重要物品。看是否能够匹配得来

 

  1 #include<cstdio>
  2 #include<memory.h>
  3 #include <iostream>
  4 using namespace std;
  5 #define repu(i, a, b) for(int i = (a); i < (b); i++)
  6 #define MAX 202
  7 bool flag,visit[MAX];    ///记录V2中的某个点是否被搜索过
  8 int match[MAX];   ///记录与V2中的点匹配的点的编号
  9 int cow, stall;   ///二分图中左边、右边集合中顶点的数目
 10 int head[MAX];
 11 struct edge
 12 {
 13     int to,next;
 14 } e[10005];
 15 int index,X,Y;
 16 void addedge(int u,int v)
 17 {
 18     ///向图中加边的算法,注意加上的是有向边
 19     ///u为v的后续节点既是v---->u
 20     e[index].to=v;
 21     e[index].next=head[u];
 22     head[u]=index;
 23     index++;
 24 }
 25 /// 匈牙利(邻接表)算法
 26 bool dfs(int u)
 27 {
 28     int i,v;
 29     for(i = head[u]; i != 0; i = e[i].next)
 30     {
 31         v = e[i].to;
 32         if(!visit[v])   ///如果节点v与u相邻并且未被查找过
 33         {
 34             visit[v] = true;   ///标记v为已查找过
 35             if(match[v] == -1 || dfs(match[v]))   ///如果i未在前一个匹配M中,或者i在匹配M中,但是从与i相邻的节点出发可以有增广路径
 36             {
 37                 match[v] = u;  ///记录查找成功记录,更新匹配M(即“取反”)
 38                 return true;   ///返回查找成功
 39             }
 40         }
 41     }
 42     return false;
 43 }
 44 int g[MAX][MAX];
 45 pair<int, int> Map[MAX][MAX];
 46 int n,m;
 47 void MaxMatch()
 48 {
 49     int i,sum=0;
 50     memset(match,-1,sizeof(match));
 51     for(i = 0; i < X; ++i)
 52     {
 53         memset(visit,false,sizeof(visit));///清空上次搜索时的标记
 54         if(dfs(i))    ///从节点i尝试扩展
 55             sum++;
 56     }
 57     printf("%d\n",sum);
 58 }
 59 void build()
 60 {
 61     int r = -1, c = -1;
 62     repu(i,1,n+1)
 63     {
 64         bool flag = true;
 65         repu(j,1,m+1)
 66         {
 67             if(g[i][j] == 1)
 68             {
 69                 ///如果没有障碍物,说明一个机器人就可以解决,否则就得加一个机器人
 70                 if(flag)
 71                     ++r;
 72                 Map[i][j].first = r;
 73                 flag = false;
 74             }
 75             if(g[i][j] == 2)
 76                 flag = true;
 77         }
 78     }
 79     repu(j,1,m+1)
 80     {
 81         bool flag = true;
 82         repu(i,1,n+1)
 83         {
 84             if(g[i][j] == 1)
 85             {
 86                 if(flag) ++c;
 87                 Map[i][j].second = c;
 88                 flag = false;
 89             }
 90             if(g[i][j] == 2) flag = true;
 91         }
 92     }
 93     X = r + 1;
 94     repu(i,1,n+1)
 95     repu(j,1,m+1)
 96     if(g[i][j] == 1)
 97     {
 98         addedge(Map[i][j].first,Map[i][j].second);
 99         cout<<Map[i][j].first<<"--"<<Map[i][j].second<<endl;
100     }
101 }
102 void init()
103 {
104     int a, x, y;
105     memset(g, 0, sizeof(g));
106     scanf("%d%d%d", &n, &m, &a);
107     while(a--)
108     {
109         scanf("%d%d", &x, &y);
110         g[x][y] = 1;
111     }
112     scanf("%d", &a);
113     while(a--)
114     {
115         scanf("%d%d", &x, &y);
116         g[x][y] = 2;
117     }
118 }
119 ///和POJ 3041的区别就是有障碍物
120 ///因为有障碍物,所以需要进行行列拆分。。。即build
121 int main()
122 {
123     int T,a,b,x,y,l,r;
124     scanf("%d",&T);
125     while(T--)
126     {
127         memset(head,0,sizeof(head));    ///切记要初始化
128         index = 1;
129         init();
130         build();
131         MaxMatch();
132     }
133     return 0;
134 }
View Code

 

 

 

 

posted @ 2015-09-03 00:11  一麻袋码的玛侬  阅读(261)  评论(0编辑  收藏  举报