zoukankan      html  css  js  c++  java
  • JZOJ 6841. 【2020.11.5提高组模拟】淘淘蓝蓝之树林(凸包+最短路)

    JZOJ 6841. 【2020.11.5提高组模拟】淘淘蓝蓝之树林

    题目大意

    • n ∗ m n*m nm的图中有一个四联通快,求从给定出发点绕该联通快一圈回到出发点的最小路径长度,该路径八联通。数据保证有解。
    • n , m ≤ 2000 n,mleq 2000 n,m2000

    题解

    • 题目中出现了绕一圈,如果想最短路相关的算法不知道怎么处理,于是想到了凸包。
    • 把中间联通快的外围外的一圈点和给定的出发点一起构出一个凸包,难道这样就做完了?
    • 有可能出发点是凹在里面的,所有可能出发点没有经过,
    • 那么需要判断如果出发点不在凸包上的话,就从出发点开始跑最短路,将离它最近的两个凸包上的点断开,分别连向它即可。
    • 注意这里凸包需要保留共线的点,不然找到的最近两个点可能会出错。
    • 另外,这题还有别的更简单的解法,
    • 可以直接找联通快最上方的某个点,用一条直线把它到整个图的上边界全部方“封住”,再从出发点开始跑一遍最短路,到这条直线两侧的距离之和就是答案。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define N 2010
    struct P{
    	int x, y;
    	long double d;
    }p[N * N], q[N * N];
    int a[N][N], vi[N][N], bz[N][N], inq[N][N], dis[N][N];
    int fx[8][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {1, -1}, {1, 1}, {-1, 1}, {-1, -1}};
    queue<P> qu;
    int sq(int x) {
    	return x * x;
    }
    int cmp(P x, P y) {
    	if(x.y == y.y) return x.x < y.x;
    	return x.y < y.y;
    }
    int cmp1(P x, P y) {
    	if(x.d == y.d) return (sq(x.x) + sq(x.y) > sq(y.x) + sq(y.y));
    	return x.d < y.d;
    }
    P de(P x, P y) {
    	return P{x.x - y.x, x.y - y.y};
    }
    int ch(P x, P y) {
    	return x.x * y.y - x.y * y.x;
    }
    int main() {
    	int n, m, i, j, k, tot = 0;
    	int S, T;
    	char c;
    	scanf("%d%d", &n, &m);
    	for(i = 1; i <= n; i++) {
    		scanf("
    ");
    		for(j = 1; j <= m; j++) {
    			scanf("%c", &c);
    			if(c == 'X') a[i][j] = 1;
    			if(c == '*') p[++tot].x = i, p[tot].y = j, vi[i][j] = 1, S = i, T = j;
    		}
    	}
    	for(i = 1; i <= n; i++) 
    		for(j = 1; j <= m; j++) if(a[i][j]) {
    			for(k = 0; k < 4; k++) {
    				int x = i + fx[k][0], y = j + fx[k][1];
    				if(x < 1 || x > n || y < 1 || y > m || a[x][y] || vi[x][y]) continue;
    				vi[x][y] = 1;
    				p[++tot].x = x, p[tot].y = y;
    			}
    		}
    	sort(p + 1, p + tot + 1, cmp);
    	for(i = 2; i <= tot; i++) p[i].d = atan2(p[i].y - p[1].y, p[i].x - p[1].x);
    	sort(p + 2, p + tot + 1, cmp1);
    	q[1] = p[1], q[2] = p[2];
    	int tp = 2;
    	for(i = 3; i <= tot; i++) {
    		while(tp > 1 && ch(de(q[tp], q[tp - 1]), de(p[i], q[tp])) < 0) tp--;
    		q[++tp] = p[i];
    	}
    	int ans = 0, ok = 0;
    	for(i = 1; i <= tp; i++) {
    		ans += max(abs(q[i % tp + 1].x - q[i].x), abs(q[i % tp + 1].y - q[i].y));
    		if(S == q[i].x && T == q[i]. y) ok = 1;
    		inq[q[i].x][q[i].y] = 1;
    	}
    	if(!ok) {
    		P x;
    		memset(dis, 127, sizeof(dis));
    		x.x = S, x.y = T;
    		dis[S][T] = 0, bz[S][T] = 1;
    		qu.push(x);
    		while(!qu.empty()) {
    			x = qu.front();
    			qu.pop();
    			for(i = 0; i < 8; i++) {
    				P y;
    				y.x = x.x + fx[i][0], y.y = x.y + fx[i][1];
    				if(y.x < 1 || y.x > n || y.y < 1 || y.y > m || a[y.x][y.y]) continue;
    				if(dis[x.x][x.y] + 1 < dis[y.x][y.y]) {
    					dis[y.x][y.y] = dis[x.x][x.y] + 1;
    					if(!bz[y.x][y.y]) {
    						bz[y.x][y.y] = 1;
    						qu.push(y);
    					}
    				}
    			}
    			bz[x.x][x.y] = 0;
    		}
    		int Mi = 1e9, mi = 1e9, xi, xj, yi, yj;
    		for(i = 1; i <= n; i++) {
    			for(j = 1; j <= m; j++) if(inq[i][j]) {
    				if(dis[i][j] <= Mi) yi = xi, yj = xj, xi = i, xj = j, mi = Mi, Mi = dis[i][j];
    				else if(dis[i][j] < mi) yi = i ,yj = j, mi = dis[i][j];
    			}
    		}
    		ans += Mi + mi - max(abs(xi - yi), abs(xj - yj));
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
    
  • 相关阅读:
    图片上传-下载-删除等图片管理的若干经验总结3-单一业务场景的完整解决方案
    图片上传-下载-删除等图片管理的若干经验总结2
    HDU 1195 Open the Lock
    HDU 1690 Bus System
    HDU 2647 Reward
    HDU 2680 Choose the best route
    HDU 1596 find the safest road
    POJ 1904 King's Quest
    CDOJ 889 Battle for Silver
    CDOJ 888 Absurdistan Roads
  • 原文地址:https://www.cnblogs.com/LZA119/p/14279514.html
Copyright © 2011-2022 走看看