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 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4179299.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值