POJ--3057(二分图匹配,BFS,二分)
2014-12-23 00:28:02
思路:这题卡了我好久....最后发现错在一个细节一个思路点(dmin判断和按时间拆门)orz....太弱了。不过最后靠自己AC还是挺开心的。
巫大叔书里的题。
首先考虑,肯定要计算每个人到各个门的距离,用BFS解决。
其次,考虑到每秒只能通过一个人,所以我们考虑按时间拆门,即:每秒钟每个门设为一个点。如果A到B门要x秒,那么可以把A和x秒及以后的B门建边。
最后,二分时间,然后根据时间建图,跑一遍二分图最大匹配,当然要每个人都能找到匹配的门才能(找到某一秒的门)。
注意细节:(1)建图时要注意根本不能连通的人和门是不能建边的(好吧...在这我犯了逗b错误)
(2)根据时间拆门的话,匹配点的总数会比较大,注意数组范围。
(3)BFS完记得检索一下,找impossible情况。
PS:这题有更高效的方法,就是逐渐增加时间,然后之前二分匹配成功的点在之后就不用再考虑了。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <iostream> 11 #include <algorithm> 12 using namespace std; 13 #define lp (p << 1) 14 #define rp (p << 1|1) 15 #define getmid(l,r) (l + (r - l) / 2) 16 #define MP(a,b) make_pair(a,b) 17 typedef long long ll; 18 typedef unsigned long long ull; 19 typedef pair<int,int> pii; 20 const int INF = 1 << 30; 21 const int maxn = 200; 22 23 int X,Y,T,cntd,cntm; 24 int first[10000],next[1000000],ver[1000000],ecnt; 25 int dmin[maxn][maxn],id[maxn][maxn]; 26 char g[maxn][maxn]; 27 int mat[10000],used[10000]; 28 int dir[4][2] = {-1,0,1,0,0,-1,0,1}; 29 30 struct node{ 31 int x,y,s; 32 node(int tx,int ty,int ts) : x(tx),y(ty),s(ts) {} 33 }; 34 35 void Add_edge(int u,int v){ 36 next[++ecnt] = first[u]; 37 ver[ecnt] = v; 38 first[u] = ecnt; 39 } 40 41 void Bfs(int sx,int sy,int door){ 42 queue<node> Q; 43 while(!Q.empty()) Q.pop(); 44 Q.push(node(sx,sy,0)); 45 while(!Q.empty()){ 46 node p = Q.front(); Q.pop(); 47 for(int i = 0; i < 4; ++i){ 48 int tx = p.x + dir[i][0]; 49 int ty = p.y + dir[i][1]; 50 if(tx >= 0 && tx < X && ty >= 0 && ty < Y && g[tx][ty] == '.'){ 51 int tag = id[tx][ty]; 52 if(dmin[door][tag] >= 0) continue; 53 dmin[door][tag] = p.s + 1; 54 Q.push(node(tx,ty,p.s + 1)); 55 } 56 } 57 } 58 } 59 60 bool Check(){ 61 for(int i = 1; i <= cntm; ++i){ 62 int flag = -1; 63 for(int j = cntm + 1; j <= cntd; ++j) 64 if(dmin[j][i] != -1) flag = dmin[j][i]; 65 if(flag == -1) return false; 66 } 67 return true; 68 } 69 70 void Build_graph(int val){ 71 memset(first,-1,sizeof(first)); 72 ecnt = 0; 73 for(int i = 1; i <= cntm; ++i){ 74 for(int j = cntm + 1; j <= cntd; ++j){ 75 if(dmin[j][i] != -1 && dmin[j][i] <= val){ 76 for(int k = dmin[j][i]; k <= val; ++k) 77 Add_edge(i,cntm + (j - cntm - 1) * val + k); 78 } 79 } 80 } 81 } 82 83 bool find(int p){ 84 for(int i = first[p]; i != -1; i = next[i]){ 85 int v = ver[i]; 86 if(used[v] == 0){ 87 used[v] = 1; 88 if(mat[v] == 0 || find(mat[v])){ 89 mat[v] = p; 90 return true; 91 } 92 } 93 } 94 return false; 95 } 96 97 bool Hungary(){ 98 int res = 0; 99 memset(mat,0,sizeof(mat)); 100 for(int i = 1; i <= cntm; ++i){ 101 memset(used,0,sizeof(used)); 102 if(find(i) == false) return false; 103 } 104 return true; 105 } 106 107 int Solve(){ 108 int l = 0,r = 110; 109 while(l < r){ 110 int mid = getmid(l,r); 111 Build_graph(mid); 112 if(Hungary()) r = mid; 113 else l = mid + 1; 114 } 115 return l; 116 } 117 118 int main(){ 119 scanf("%d",&T); 120 while(T--){ 121 memset(id,0,sizeof(id)); 122 memset(dmin,-1,sizeof(dmin)); 123 cntm = cntd = 0; 124 scanf("%d%d",&X,&Y); 125 for(int i = 0; i < X; ++i) scanf("%s",g[i]); 126 for(int i = 0; i < X; ++i) 127 for(int j = 0; j < Y; ++j) 128 if(g[i][j] == '.') id[i][j] = ++cntm; 129 cntd = cntm; 130 for(int i = 0; i < X; ++i) 131 for(int j = 0; j < Y; ++j) 132 if(g[i][j] == 'D'){ 133 id[i][j] = ++cntd; 134 Bfs(i,j,cntd); 135 } 136 if(Check() == false) printf("impossible\n"); 137 else printf("%d\n",Solve()); 138 } 139 return 0; 140 }