loj 1150(spfa预处理+二分+最大匹配)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26864

思路:首先是spfa预处理出每个'G'到'H'的最短距离,然后就是二分最大距离,最大匹配验证即可。

PS:这道题一开始没什么思路,然后想先最简单的spfa预处理写一下吧,然后写着写着就突然豁然开朗,有思路了!然后就AC了!

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<vector>
  7 using namespace std;
  8 #define MAXN 55
  9 #define inf 1<<30
 10 #define FILL(a,b) memset(a,b,sizeof(a))
 11 
 12 vector<pair<int,int> >g,h;
 13 
 14 int n,dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
 15 int dist[MAXN][MAXN],dd[MAXN][MAXN];
 16 bool mark[MAXN][MAXN];
 17 char map[MAXN][MAXN];
 18 
 19 void spfa(int vs)
 20 {
 21     FILL(mark,false);
 22     for(int i=0;i<MAXN;i++)
 23         for(int j=0;j<MAXN;j++)dd[i][j]=inf;
 24     queue<pair<int,int> >que;
 25     que.push(make_pair(g[vs].first,g[vs].second));
 26     dd[g[vs].first][g[vs].second]=0;
 27     while(!que.empty()){
 28         pair<int,int>p=que.front();
 29         que.pop();
 30         mark[p.first][p.second]=false;
 31         for(int i=0;i<4;i++){
 32             int x=p.first+dir[i][0],y=p.second+dir[i][1];
 33             if(x>=0&&x<n&&y>=0&&y<n&&map[x][y]!='#'){
 34                 if(dd[p.first][p.second]+1<dd[x][y]){
 35                     dd[x][y]=dd[p.first][p.second]+1;
 36                     if(!mark[x][y]){
 37                         mark[x][y]=true;
 38                         que.push(make_pair(x,y));
 39                     }
 40                 }
 41             }
 42         }
 43     }
 44 }
 45 
 46 vector<int>gg[MAXN];
 47 void Build(int limit)
 48 {
 49     for(int i=0;i<MAXN;i++)gg[i].clear();
 50     for(int i=0;i<g.size();i++){
 51         for(int j=0;j<h.size();j++){
 52             if(dist[i][j]<=limit)gg[i].push_back(j);
 53         }
 54     }
 55 }
 56 
 57 int ly[MAXN];
 58 bool vis[MAXN];
 59 
 60 int dfs(int u)
 61 {
 62     for(int i=0;i<gg[u].size();i++){
 63         int v=gg[u][i];
 64         if(!vis[v]){
 65             vis[v]=true;
 66             if(ly[v]==-1||dfs(ly[v])){
 67                 ly[v]=u;
 68                 return 1;
 69             }
 70         }
 71     }
 72     return 0;
 73 }
 74 
 75 int MaxMatch()
 76 {
 77     int res=0;
 78     FILL(ly,-1);
 79     for(int i=0;i<g.size();i++){
 80         FILL(vis,false);
 81         res+=dfs(i);
 82     }
 83     return res;
 84 }
 85 
 86 int main()
 87 {
 88     int _case,t=1;
 89     scanf("%d",&_case);
 90     while(_case--){
 91         scanf("%d",&n);
 92         g.clear();
 93         h.clear();
 94         for(int i=0;i<n;i++)scanf("%s",map[i]);
 95         for(int i=0;i<n;i++){
 96             for(int j=0;j<n;j++){
 97                 if(map[i][j]=='G')g.push_back(make_pair(i,j));
 98                 else if(map[i][j]=='H')h.push_back(make_pair(i,j));
 99             }
100         }
101         for(int i=0;i<MAXN;i++)
102             for(int j=0;j<MAXN;j++)dist[i][j]=inf;
103         for(int i=0;i<g.size();i++){
104             spfa(i);
105             for(int j=0;j<h.size();j++){
106                 if(dd[h[j].first][h[j].second]!=inf)dist[i][j]=min(dist[i][j],2*dd[h[j].first][h[j].second]+2);
107             }
108         }
109         int low=inf,high=0,mid,ans=inf;
110         for(int i=0;i<g.size();i++){
111             for(int j=0;j<h.size();j++){
112                 if(dist[i][j]!=inf){
113                     low=min(low,dist[i][j]);
114                     high=max(high,dist[i][j]);
115                 }
116             }
117         }
118         while(low<=high){
119             mid=(low+high)>>1;
120             Build(mid);
121             if(MaxMatch()==(int)h.size()){
122                 ans=mid;
123                 high=mid-1;
124             }else
125                 low=mid+1;
126         }
127         printf("Case %d: ",t++);
128         if(ans!=inf){
129             printf("%d\n",ans);
130         }else
131             puts("Vuter Dol Kupokat");
132     }
133     return 0;
134 }
View Code

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值