题意:给定一个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 ",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 }