zoukankan      html  css  js  c++  java
  • 题解-CF677D Vanya and Treasure

    CF677D Vanya and Treasure

    有一个 (n imes m) 的矩阵 (a(1le a_{i,j}le p)),求从起点 ((1,1)) 出发依次遍历值为 (1 o p) 的矩阵单元的最短路径曼哈顿距离。保证满足 (a_{i,j}=p)((i,j)) 唯一。

    数据范围:(1le n,mle 300)(1le ple ncdot m)


    先记录 ( t vector) 数组 (w)(w_t) 表示 (a_{i,j}=t) 的位置集合。

    (w_t) 的每个元素有三个属性:(x,y,g)(x)(y) 是位置坐标,(g) 是出发遍历矩阵值 (1 o t) 后到 ((x,y)) 的最短路径长度。


    暴力做法:从 (w_{i-1}) 的所有 (g) 值递推 (w_i) 的所有 (g) 值:

    [u.g=min_{vin w_{i-1}}{v.g+{ m abs}(u.x-v.x)+{ m abs}(u.y-v.y)}(uin w_i) ]

    时间复杂度 (Thetaleft(sum_{iin[2,p]}|w_{i-1}|cdot |w_i| ight)leTheta(n^2m^2))

    image.png

    • 怎么卡到 (Theta(n^2m^2)) 的?

    比如 (n=300,m=300,p=2),矩阵一半是 (1) 一半是 (2)


    这题的优化是真的巧,反正我比赛时没想到。

    考虑以下情况:

    [forall iin[2,p]:|w_{i-1}|cdot|w_i|le ncdot m ]

    总的时间复杂度是:

    [Thetaleft(sum_{iin[2,p]}|w_{i-1}|cdot |w_i| ight) ]

    同时满足 (sum_{i=1}^p |w_i|=ncdot m),根据柯西不等式:

    [egin{split} &left(sum_{i=2}^p|w_{i-1}|cdot |w_i| ight)^2\ le&sum_{i=1}^{p-1}|w_i|^2sum_{i=2}^{p}|w_i|^2\ le&left(sum_{i=1}^{p}|w_i|^2 ight)^2\ le&left(sqrt{ncdot m} imesleft(sqrt{ncdot m} ight)^2 ight)^2 end{split} ]

    所以 (sum_{i=2}^p|w_{i-1}|cdot |w_i|le ncdot m imessqrt{ncdot m})

    复杂为 (Theta(ncdot msqrt{ncdot m})) 可以通过。


    但是如果 (exists iin[2,p]:|w_{i-1}|cdot|w_i|>ncdot m) 怎么办呢?

    可以套个 (Theta(V))多源无向无权图最短路模板 ( t Bfs)

    所以此时单次递推的时间复杂度也是 (Theta(ncdot m))

    这样的单次递推与 (|w_{i-1}|cdot|w_i|=ncdot m) 相比:

    1. 一次递推时间复杂度相等。

    2. 由于对于这个 (i)(|w_{i-1}|cdot|w_i|) 大,所以对于其他 (i)(|w_{i-1}|cdot|w_i|) 较小。所以总时间复杂度小。

    所以这样优化后总时间复杂度 (le Theta(ncdot msqrt{ncdot m}))可以通过。


    • 代码:
    //Data
    const int N=3e2;
    int n,m,k,a[N+7][N+7];
    struct node{
    	int x,y,g;
    	node(int X=0,int Y=0,int G=0){x=X,y=Y,g=G;}
    };
    vector<node> w[N*N+7];
    
    //Bfs
    int d[N+7][N+7];
    int tx[]={0,0,-1,1},ty[]={-1,1,0,0};
    int ok(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=m;}
    void Bfs(vector<node>&s){ //多源无向无权图最短路模板 Bfs。
    	vector<node> q;
    	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) d[i][j]=inf;
    	int sc=-1;
    	q.pb(s[++sc]);
    	for(int i=0;i<sz(q);i++){
    		node v=q[i];
    		while(sc+1<sz(s)&&s[sc+1].g<=v.g) q.pb(s[++sc]);
    		for(int t=0;t<4;t++){
    			node u=node(v.x+tx[t],v.y+ty[t]);
    			if(ok(u.x,u.y)&&v.g+1<d[u.x][u.y]) d[u.x][u.y]=u.g=v.g+1,q.pb(u);
    		}
    	}
    }
    
    //Main
    int main(){
    	scanf("%d%d%d",&n,&m,&k);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			scanf("%d",&a[i][j]);
    			if(a[i][j]==1) w[a[i][j]].pb(node(i,j,i+j-2));
    			else w[a[i][j]].pb(node(i,j,inf));
    		}
    	for(int key=2;key<=k;key++){
    		if(sz(w[key-1])*sz(w[key])<=n*m){
    			for(node&u:w[key]) for(node v:w[key-1])
    				u.g=min(u.g,v.g+abs(u.x-v.x)+abs(u.y-v.y));
    		} else {
    			vector<node> s;
    			for(node v:w[key-1]) s.pb(v);
    			Bfs(s);
    			for(node&u:w[key]) u.g=d[u.x][u.y];
    		}
    	}
    	printf("%d
    ",w[k][0].g);
    	return 0;
    }
    

    祝大家学习愉快!

  • 相关阅读:
    mysql数据库管理工具(navicat for mysql)
    一次测试岗位针对Java和接口的面试题
    接口测试 rest-assured 使用指南
    简单实现接口自动化测试(基于python+unittest)
    负载测试、压力测试和性能测试的异同
    【Excle数据透视表】如何新建数据透视表样式
    【Excle数据透视表】如何为数据透视表应用样式
    【Linux】Linux删除指定文件夹下面 名称不包含指定字符的文件
    【Excle数据透视表】如何水平并排显示报表筛选区域的字段
    【Excle数据透视表】如何在数据透视表中使用合并单元格标志
  • 原文地址:https://www.cnblogs.com/George1123/p/12944085.html
Copyright © 2011-2022 走看看