[JZOJ3106]锻炼

题目大意:
  给你一个$n\times m(n,m\leq 50)$的网格图,其中有一个四连通的障碍物。给定起点和终点,每次你可以走到和当前位置八连通的一个方格内,问绕障碍物一圈最短要走几格?

思路:
  BFS求一下最短路,然后当一个点被访问两次时,把两次的最短路加起来即可。
  然而这样显然是错的,因为并不能保证两次的路径刚好把障碍物包住,因此我们还需知道每条路径是从障碍物哪边绕过来的。
  一种方法是使用扫描线,当两条路径会合时,从障碍物内一点发射一条扫描线,如果和最短路橡胶的次数时奇数,那么肯定是将障碍物包住了。
  这样据说已经能过了,不过还有一种更妙的方法。
  可以在BFS最短路时,同时记录这条最短路与扫描线相交的次数的奇偶性。
  具体方法是,每次最短路往外扩展一格时,判断一下本次扩展是否经过了扫描线。
  最后两条最短路会合时,只需要判断一下两个最短路经过次数加起来是否为奇数,如果是,则说明将障碍物包起来了,更新答案。

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cctype>
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 inline char getblock() {
12     register char ch;
13     do {
14         ch=getchar();
15     } while(ch!='.'&&ch!='X'&&ch!='*');
16     return ch;
17 }
18 typedef std::pair<int,int> Block;
19 const int N=50;
20 const int inf=0x7fffffff;
21 const int dx[]={-1,-1,-1,0,0,1,1,1},dy[]={-1,0,1,-1,1,-1,0,1};
22 Block s;
23 bool f[N][N];
24 int n,m,dis[N][N];
25 std::queue<Block> q;
26 inline bool check(const Block &u) {
27     return ~u.first&&u.first<n&&~u.second&&u.second<m&&~dis[u.first][u.second];
28 }
29 inline bool calc(const Block &u,const Block &v) {
30     return (u.first==s.first&&u.second>s.second&&v.first<s.first)||(v.first==s.first&&v.second>s.second&&u.first<s.first);
31 }
32 int main() {
33     n=getint(),m=getint();
34     for(register int i=0;i<n;i++) {
35         for(register int j=0;j<m;j++) {
36             const char ch=getblock();
37             if(ch=='*') q.push((Block){i,j});
38             if(ch=='X') {
39                 s=(Block){i,j};
40                 dis[i][j]=-1;
41             }
42             if(ch=='.') dis[i][j]=inf;
43         }
44     }
45     int ans=inf;
46     while(!q.empty()) {
47         const Block u=q.front();
48         q.pop();
49         for(register int i=0;i<8;i++) {
50             const Block v=(Block){u.first+dx[i],u.second+dy[i]};
51             if(!check(v)) continue;
52             if(dis[v.first][v.second]==inf) {
53                 q.push(v);
54                 dis[v.first][v.second]=dis[u.first][u.second]+1;
55                 f[v.first][v.second]=f[u.first][u.second]^calc(u,v);
56             } else {
57                 if(f[u.first][u.second]^calc(u,v)^f[v.first][v.second]) {
58                     ans=std::min(ans,dis[u.first][u.second]+dis[v.first][v.second]+1);
59                 }
60             }
61         }
62     }
63     printf("%d\n",ans);
64     return 0;
65 }

 

posted @ 2018-01-08 12:34  skylee03  阅读(107)  评论(0编辑  收藏  举报