hdu 3468(二分匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3468

大牛思路:

用BFS找出每一个集合点到其它可达点的距离以及这个集合点到下一集合点的距离

枚举是否能从一个集合点K经过一个宝物点X到达下一个集合点(K+1).如果能的话,则path[K][X]=true;

 如果发现有一个集合点不可达的话,则输出-1;

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 #define MAXN 110
  8 char map[MAXN][MAXN];
  9 int dd[MAXN];//保存相邻集合点之间的距离
 10 int dist[MAXN][MAXN*MAXN];//保存集合点到图中任意一点之间的距离
 11 bool mark[MAXN*MAXN];
 12 bool path[MAXN][MAXN*MAXN];//标记二部图x与y的连通性
 13 int match[MAXN*MAXN];//匹配
 14 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
 15 int n,m,p,q;
 16 
 17 int GetId(char ch){
 18     if(ch>='A'&&ch<='Z')return ch-'A';
 19     return ch-'a'+26;
 20 }
 21 
 22 void bfs(int x,int y,int id){
 23     queue<int>Q;
 24     Q.push(x),Q.push(y);
 25     dist[id][x*m+y]=0;
 26     while(!Q.empty()){
 27         x=Q.front();Q.pop();
 28         y=Q.front();Q.pop();
 29         int d=dist[id][x*m+y];
 30         for(int i=0;i<4;i++){
 31             int xx=x+dir[i][0];
 32             int yy=y+dir[i][1];
 33             if(xx>=0&&xx<n&&yy>=0&&yy<m&&map[xx][yy]!='#'&&dist[id][xx*m+yy]==-1){
 34                 dist[id][xx*m+yy]=d+1;
 35                 Q.push(xx),Q.push(yy);
 36                 if(isalpha(map[xx][yy])&&(GetId(map[xx][yy])==id+1)){
 37                     dd[id]=d+1;
 38                 }
 39             }
 40         }
 41     }
 42 }
 43 
 44 
 45 
 46 bool dfs(int k,int m){
 47     for(int i=0;i<m;i++){
 48         if(path[k][i]&&!mark[i]){
 49             mark[i]=true;
 50             if(match[i]==-1||dfs(match[i],m)){
 51                 match[i]=k;
 52                 return true;
 53             }
 54         }
 55     }
 56     return false;
 57 }
 58 
 59 
 60 int Hungary(int n,int m){
 61     int ans=0;
 62     memset(match,-1,sizeof(match));
 63     for(int i=0;i<n;i++){
 64         memset(mark,false,sizeof(mark));
 65         if(dfs(i,m))ans++;
 66     }
 67     return ans;
 68 }
 69 
 70 
 71 int main(){
 72     while(~scanf("%d%d",&n,&m)){
 73         memset(dist,-1,sizeof(dist));
 74         memset(dd,-1,sizeof(dd));
 75         memset(path,false,sizeof(path));
 76         p=q=0;
 77         for(int i=0;i<n;i++){
 78             scanf("%s",map[i]);
 79         }
 80         for(int i=0;i<n;i++){
 81             for(int j=0;j<m;j++){
 82                 if(isalpha(map[i][j])){
 83                     p=max(p,GetId(map[i][j]));
 84                     bfs(i,j,GetId(map[i][j]));
 85                 }
 86             }
 87         }
 88         bool flag=true;
 89         for(int i=0;i<p;i++){
 90             if(dd[i]==-1){ flag=false;break; }
 91         }
 92         if(!flag){ puts("-1");continue; }
 93         for(int i=0;i<n;i++){
 94             for(int j=0;j<m;j++){
 95                 if(map[i][j]=='*'){
 96                     for(int k=0;k<p;k++){
 97                         //判断金子是否在最短路上
 98                         if(dist[k][i*m+j]+dist[k+1][i*m+j]==dd[k]){
 99                             path[k][q]=true;
100                         }
101                     }
102                     q++;
103                 }
104             }
105         }
106         printf("%d\n",Hungary(p+1,q));
107     }
108     return 0;
109 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值