zoukankan      html  css  js  c++  java
  • 「JOI Open 2019」病毒实验(bfs+Boruvka算法思想):

    https://loj.ac/problem/3155

    题解:

    考虑先预处理一个数组mx[S],其中S是一个二进制状态,记录着四个方向是否有病毒,在这种情况下,在那个字符串环上的最长连续段(注意这是个无限长的环,最长连续段可以是+∞)。

    那么得到一种暴力的做法,枚举起点,然后宽搜,对于每一个点,在预处理之后,是可以(O(1))判断是否会被感染的。

    因为我们要求的是最小的,考虑如果以u作为起点,能走到v,那么v的答案比起u只会小不会大。

    考虑把矩阵划分成若干块,一开始每个点自己为一块。

    每一块里有一个至少特殊点x(我们只记录一个就好了),以这个块的所有点作为起点,都能感染到这个特殊点。

    每次枚举一个块A,从A的特殊点开始宽搜,如果走到另一个块B的点,那么就把A和B合并到一起,新的特殊点是B原来的特殊点。

    如果一个块,不能走到其它块去,便用它更新答案,特殊点能遍历到的点数便是这个块的最小答案,同时是方案数。

    这么做复杂度还是没有保证,会被卡到(O((nm)^2))

    考虑Boruvka算法求最小生成树是怎么做的:

    每次给每一个联通块找一条出边,每次做完,必定能使联通块个数/2,所以只用做log次。

    对这题,是一样的,每次先给每一个块A找一个要合并的B:
    注意!这一层里,如果通过A找到了相邻的B,把A合并到B后,那么这一层里不能再用B的特殊点BFS,原因是这样可能重复经过A的点,这就是会被卡的原因,但是,如又有其它的C找到B,把C合并到B,是没有问题的。

    复杂度:(O(nm~log~nm))

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    int t, n, m;
    
    int mov[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    
    int zh(char c) {
    	if(c == 'N') return 0;
    	if(c == 'E') return 1;
    	if(c == 'S') return 2;
    	return 3;
    }
    
    const int M = 2e5 + 5;
    
    char str[M]; int c[M];
    
    const int N = 805;
    
    int a[N][N];
    
    void Init() {
    	scanf("%d %d %d", &t, &n, &m);
    	scanf("%s", str + 1);
    	fo(i, 1, t) c[i] = c[i + t] = zh(str[i]);
    	fo(i, 1, n) fo(j, 1, m) {
    		scanf("%d", &a[i][j]);
    	}
    }
    
    int mx[16];
    
    void build() {
    	fo(s, 0, 15) {
    		int l = 0;
    		fo(j, 1, 2 * t + 1)	if(j > 2 * t || !(s >> c[j] & 1)) {
    			mx[s] = max(mx[s], l);
    			l = 0;
    		} else l ++;
    		if(mx[s] == 2 * t) mx[s] = 1e5;
    	}
    }
    
    int bz[N][N], bz0;
    
    int pd(int x, int y) {
    	if(a[x][y] == 0) return 0;
    	int s = 0;
    	fo(j, 0, 3) {
    		int u = x + mov[j][0], v = y + mov[j][1];
    		s += (1 << j) * (bz[u][v] == bz0);
    	}
    	return a[x][y] <= mx[s];
    }
    
    #define pb push_back
    
    int id[N][N], f[N * N];
    int d[N * N][2], d0;
    int ok[N][N], us[N * N];
    vector<int> g[N * N];
    
    void work() {
    	fo(i, 1, n) fo(j, 1, m) {
    		id[i][j] = (i - 1) * m + j;
    		f[id[i][j]] = id[i][j];
    		g[id[i][j]].pb(id[i][j]);
    		if(a[i][j] == 0) ok[i][j] = 1;
    	}
    	int ans = 1e9, ans2 = 0;
    	while(1) {
    		int br = 1;
    		fo(i, 1, n * m) us[i] = 0;
    		fo(sx, 1, n) fo(sy, 1, m) if(!us[id[sx][sy]] && !ok[sx][sy]) {
    			br = 0;
    			bz0 ++;
    			int w = id[sx][sy];
    			d[d0 = 1][0] = sx; d[1][1] = sy;
    			bz[sx][sy] = bz0;
    			int fin = 1;
    			for(int i = 1; i <= d0; i ++) {
    				int x = d[i][0], y = d[i][1];
    				fo(j, 0, 3) {
    					int u = x + mov[j][0], v = y + mov[j][1];
    					if(u && v && u <= n && v <= m && bz[u][v] != bz0 && pd(u, v)) {
    						if(f[id[u][v]] == f[id[x][y]]) {
    							d[++ d0][0] = u; d[d0][1] = v;
    							bz[u][v] = bz0;
    						} else {
    							int q = f[id[u][v]];
    							ff(k, 0, g[w].size()) {
    								f[g[w][k]] = q;
    								g[q].pb(g[w][k]);
    							}
    							g[w].clear();
    							us[q] = 1; ok[sx][sy] = 1;
    							fin = 0; break;
    						}
    					}
    				}
    				if(!fin) break;
    			}
    			if(fin) {
    				if(d0 < ans)
    					ans = ans2 = d0; else
    				if(d0 == ans)
    					ans2 += d0;
    				ok[sx][sy] = 1;
    			}
    		}
    		if(br) break;
    	}
    	pp("%d
    %d
    ", ans, ans2);
    }
    
    int main() {
    	Init();
    	build();	
    	work();
    }
    
  • 相关阅读:
    图解SQL的Join(转)
    phpmyadmin 自动登录的办法
    ajax的data传参的两种方式
    如何在vue里面访问php?
    vue 路由部署服务器子目录问题
    Vuthink正确安装过程
    关于vueThink框架打包发布的一些问题
    使用npm安装依赖,尽量别使用cnpm,会漏掉很多依赖的
    phpstorm(或webstorm) 打开后 一直停留在scanning files to index....,或跳出内存不够的提示框
    vuethink 配置
  • 原文地址:https://www.cnblogs.com/coldchair/p/12398836.html
Copyright © 2011-2022 走看看