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 }

 

posted @ 2014-12-23 00:35  Naturain  阅读(642)  评论(0编辑  收藏  举报