zoukankan      html  css  js  c++  java
  • Codeforces 677D Vanya and Treasure (dp&树状数组 | 暴力)

    Vanya and Treasure

    题目大意,有n*m(n<=m<=300)的格子,有p个宝箱,现在你在(1,1)拥有种类1宝箱的钥匙,当你打开k号宝箱时会得到k+1号宝箱的钥匙,第p种宝箱有且只有一个,问至少要走多少步才能得到第p宝箱。

    首先并没与什么套路可循,只有硬着头皮dp一波,心想暴力绝对超时(好吧,打脸了),我的做法是dp,不难定义出这样的状态dp[i][j]表示走到(i,j)的最小路程,就会得到这样的转移方程

    dp[i][j] = dp[lasti][lastj]+|lasti-i|+|lastj-j| && d[lasti][lastj]+1 = d[i][j]那么这样的复杂度就是n^2*m^2.

    我们再将式子打开,dp[i][j] = (dp[lasti][lastj]+lasti+lastj)-i-j 暂时不考虑符号问题,我们会得到只关于(lasti,lastj)的式子,那么我们就可以通过树状数组来优化区间.

    得到转移方程:

    dp[i][j] = Min(dp[lasti][lastj]-lasti-lastj)+i+j//从左上转移而来

    dp[i][j] = Min(dp[lasti][lastj]+lasti-lastj)-i+j//  左下

    dp[i][j] = Min(dp[lasti][lastj]+lasti+lastj)-i-j//  右下

    dp[i][j] = Min(dp[lasti][lastj]-lasti+lastj)+i-j//  右上

    4个树状数组去维护,m*n*logm*logn

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #define  lowbit(i) i&-i
    using namespace std;
    const int maxn = 310;
    #define clr(a,b) memset(a,b,sizeof(a))
    
    /*
    dp[i][j] = (dp[lasti][lastj]-lasti-lastj)+i+j;0
    dp[i][j] = (dp[lasti][lastj]-lasti+lastj)+i-j;1
    dp[i][j] = (dp[lasti][lastj]+lasti+lastj)-i-j;2
    dp[i][j] = (dp[lasti][lastj]+lasti-lastj)-i+j;3
    */
    
    const int inf = (1<<30);
    
    
    struct node{int x,y;};
    vector <node>gap[maxn*maxn];
    int dp[maxn][maxn];
    int n,m,p;
    struct BIT{
    	int a,b;
    	int c[maxn][maxn];
    	int h[maxn][maxn];
    	void init(){clr(h,0);}
    	
    	void update(int high,int x,int y,int mi){
    		for(int i = x;i <= maxn;i += lowbit(i)){
    			for(int j = y;j <= maxn;j += lowbit(j)){
    				if(h[i][j] != high)h[i][j] = high,c[i][j] = inf;
    				c[i][j] = min(c[i][j],mi);
    			}
    		}
    	}
    	
    	int query(int high,int x,int y){
    		int res = inf;
    		for(int i = x;i >= 1;i-=lowbit(i)){
    			for(int j = y;j >= 1;j-=lowbit(j)){
    				if(h[i][j] == high)res = min(res,c[i][j]);
    			}
    		}
    		return res;
    	}
    }bit[4];
    
    void up(int d,int x,int y){
    	bit[0].update(d,x,y,dp[x][y]-x-y);
    	bit[1].update(d,x,m-y+1,dp[x][y]-x+y);
    	bit[2].update(d,n-x+1,m-y+1,dp[x][y]+x+y);
    	bit[3].update(d,n-x+1,y,dp[x][y]+x-y);
    }
    
    void qu(int d,int x,int y){
    	int &res = dp[x][y];res = inf;
    	res = min(res,bit[0].query(d-1,x,y)+x+y);
    	res = min(res,bit[1].query(d-1,x,m-y+1)+x-y);
    	res = min(res,bit[2].query(d-1,n-x+1,m-y+1)-x-y);//***
    	res = min(res,bit[3].query(d-1,n-x+1,y)-x+y);
    }
    
    int main(){
    	scanf("%d%d%d",&n,&m,&p);
    	for(int i = 1;i <= n;++i){
    		for(int j = 1;j <= m;++j){
    			int x;
    			scanf("%d",&x);
    			gap[x].push_back((node){i,j});
    		}
    	}
    	for(int i = 0;i < 4;++i)bit[i].init();
    	for(int i = 0;i < (int)gap[1].size();++i){
    		node p = gap[1][i];
    		int x = p.x,y = p.y;
    		dp[x][y] = x-1+y-1;
    //		printf("%d %d %d
    ",x,y,dp[x][y]);
    		up(1,x,y);
    	}
    	for(int d = 2;d <= p;++d){
    		for(int i = 0;i < (int)gap[d].size();++i){
    			node p = gap[d][i];int x = p.x,y = p.y;
    			qu(d,x,y);
    		}
    		for(int i = 0;i < (int)gap[d].size();++i){
    			node p = gap[d][i];int x = p.x,y = p.y;
    			up(d,x,y);
    		}
    	}
    	int x = gap[p][0].x,y = gap[p][0].y;
    	printf("%d
    ",dp[x][y]);
    //	for(int i = 1;i <= n;++i)for(int j = 1;j <= m;++j)
      //  printf("%d %d %d
    ",i,j,dp[i][j]);
    	return 0;
    }
    

      

    然而ggbbgg的暴力我也是zhui了直接爆搜,复杂度分析也不会,反正就是很玄学啦

    #include<cstdlib>
    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int Maxn = 305;
    const int dx[] = { 1,-1,0,0 };
    const int dy[] = { 0,0,-1,1 };
    template <class T>
    inline T Read(T& a) {
    	a = 0; char c = getchar();
    	while (c <'0' || c >'9') c = getchar();
    	while (c >= '0'&&c <= '9') {
    		a = (a << 3) + (a << 1) + c - '0';
    		c = getchar();
    	}
    	return a;
    }
    template <class T>
    void clear(T& A) {
    	while (!A.empty()) A.pop();
    }
    #define inside(a,b) ((a)>0&&(a)<=(b))
    inline int dist(int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); }
    struct node{
    	int x, y, dis;
    	node(){}
    	node(int a, int b, int c) {
    		x = a; y = b; dis = c;
    	}
    	bool operator < (const node& A)const {
    		if (dis == A.dis) return x < A.x;
    		return dis < A.dis;
    	}
    };
    typedef pair<int, int>pii;
    vector<pii>point[Maxn * Maxn];
    int dp[Maxn][Maxn], n, m;
    const int INF = 1 << 30;
    int d[Maxn][Maxn];
    void bfs(const int& nowkey,const int& curs,const int& lasts) {
    	memset(d, -1, sizeof(d));
    	vector<node>lst;
    	queue<node>q;
    	lst.clear(); clear(q);
    	for (int i = 0; i < lasts; ++i) {
    		int _x = point[nowkey - 1][i].first, _y = point[nowkey - 1][i].second;
    		lst.push_back(node(_x, _y, dp[_x][_y]));
    	}
    	sort(lst.begin(), lst.end());
    	int head = 0;
    	q.push(lst[head++]);
    	while (!q.empty()) {
    		int nx = q.front().x, ny = q.front().y, nd = q.front().dis;
    		q.pop();
    		while (head < lasts&&lst[head].dis <= nd)q.push(lst[head++]);
    		for (int i = 0; i < 4; ++i) {
    			int _x = nx + dx[i], _y = ny + dy[i];
    			if (inside(_x, n) && inside(_y, m) && !(~d[_x][_y])) {
    				d[_x][_y] = nd + 1;
    				q.push(node(_x, _y, d[_x][_y]));
    			}
    		}
    	}
    	for (int i = 0; i < curs; ++i) {
    		int _x = point[nowkey][i].first, _y = point[nowkey][i].second;
    		dp[_x][_y] = d[_x][_y];
    	}
    }
    
    int main() {
    	int p, a;
    	Read(n); Read(m); Read(p);
    	for (int i = 1; i <= n; ++i) 
    		for (int j = 1; j <= m; ++j) {
    			Read(a);
    			point[a].push_back(make_pair(i, j));
    			if (a == 1) {
    				dp[i][j] = i + j - 2;
    			}else{
    				dp[i][j] = INF;
    			}
    		}
    	for (int i = 2; i <= p; ++i) {
    		int curs = point[i].size();
    		int lasts = point[i - 1].size();
    		if (curs*lasts <= n * m) {//控制这一层复杂度比m*n小 
    			for (int j = 0; j < curs; ++j) {
    				int nowx = point[i][j].first, nowy = point[i][j].second;
    				for (int k = 0; k < lasts; ++k) {
    					int lastx = point[i - 1][k].first, lasty = point[i - 1][k].second;
    					dp[nowx][nowy] = min(dp[nowx][nowy], dp[lastx][lasty] + dist(nowx, nowy, lastx, lasty));
    				}
    			}
    		}
    		else bfs(i,curs,lasts);//如果裸的dp比m*n还大那么不如原始的爆搜 
    	}
    	printf("%d", dp[point[p][0].first][point[p][0].second]);
    	return 0;
    }
    

      

  • 相关阅读:
    经典SQL语句大全
    主键,外键,主键表,外间表
    一个不错的shell 脚本教程 入门级
    初窥Linux 之 我最常用的20条命令
    try catch finally 用法
    一个初学者对于MVC架构的理解
    第二次阶段冲刺2(6月1号)
    第二次阶段冲刺1(5月31号)
    学习进度条十三(第14周)
    学习进度条十二(第13周)
  • 原文地址:https://www.cnblogs.com/xgtao984/p/5708707.html
Copyright © 2011-2022 走看看