zoukankan      html  css  js  c++  java
  • 记录一个Heisenbug!

    记录一个错误的正确!!!
    我觉得归功于编译器
    我要学编译原理!!!


    问题是这样的
    传送门:
    https://www.luogu.org/problemnew/show/P4009
    给定一个 N imes NN×N 的方形网格,设其左上角为起点◎,坐标(1,1)(1,1),XX 轴向右为正, YY 轴向下为正,每个方格边长为 1。

    一辆汽车从起点◎出发驶向右下角终点▲,其坐标为 (N,N)(N,N)。

    在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:

    汽车只能沿网格边行驶,装满油后能行驶 KK 条网格边。出发时汽车已装满油,在起点与终点处不设油库。

    汽车经过一条网格边时,若其 XX 坐标或 YY 坐标减小,则应付费用 BB ,否则免付费用。

    汽车在行驶过程中遇油库则应加满油并付加油费用 AA。

    在需要时可在网格点处增设油库,并付增设油库费用 CC(不含加油费用AA )。

    N,K,A,B,CN,K,A,B,C 均为正整数, 且满足约束: 2leq Nleq 100,2 leq K leq 102≤N≤100,2≤K≤10。

    设计一个算法,求出汽车从起点出发到达终点所付的最小费用。


    这是一个我不是很会的题
    后来了解到用BFS暴力可解

    然后写了朴素的暴力广搜

    #include<stdio.h>
    
    typedef struct{
    	int x;
    	int y;
    	int fee;
    	int oil;
    }Status; 
    
    int dir[4][3] = {{-1,0,0},{0,-1,0},{1,0,0},{0,1,0}};//←,↑,→,↓ 
    
    int main(){
    	int N,K,A,B,C;
    	scanf("%d%d%d%d%d",&N,&K,&A,&B,&C);
    	dir[0][2] =  dir[1][2] = B;//回退费用 
    	char map[105][105]={0};
    	for(int i = 1;i<=N;i++){
    		for(int j = 1;j<=N;j++){
    			scanf("%d",&map[i][j]);
    		}
    	}
    	
    	Status status[100000];
    	int left = 0, right = 0;
    	int tx, ty, tfee;
    	int minFee = 0x3f3f3f3f;
    	status[right++] = {1,1,0,K};//起始位置 
    	
    	while(left<=right){//BFS
    		Status t = status[left++];
    		if(t.x == N || t.y == N)continue;
    		for(int i = 0;i<4;i++){
    			tx = t.x+dir[i][0];
    			ty = t.y+dir[i][1];
    			if(tx == N && ty == N){//到达终点 
    				minFee = t.fee>minFee?minFee:t.fee;
    				break;
    			}
    			if(tx<1||tx>N||ty<1||ty>N)continue;
    			status[right].x = tx;
    			status[right].y = ty;
    			status[right].oil = t.oil - 1;
    			tfee = t.fee+dir[i][2];//方向收费
    			if(map[tx][ty]==1){//加油站 
    				tfee += A;
    				status[right].oil = K; 
    			}else if(t.oil==1){//半路没油 前面保证(tx,ty)没到终点 
    				tfee += C+A;
    				status[right].oil = K;
    			}
    			status[right++].fee = tfee;
    		}
    	}
    	printf("%d
    ",minFee);
    	return 0;
    } 
    

    可以看到这里我忘记判断有没有形成环路

    然而我在DEVC++中运行 居然可以得到正确结果!
    稳定地得到正确结果
    在这里插入图片描述
    惊讶!一直不太相信的DEV环境居然能把这种优化掉

    估计是爆数组后,程序就停下了。刚好最优结果存在。

    我在VS里一直是死循环。。。
    想半天没有想通为啥死循环,调试了才知道。。
    I’m Vegetable. : (


    2019/4/23


    甚至第一版代码中
    while(left<=right){}中
    第一个if循环判断条件
    if(t.x == N || t.y == N)
    都写错了 应该是&&的
    真不知道是怎么出正确结果的 摊手


    更新正确答案

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    
    typedef struct {
    	int x;
    	int y;
    	int fee;
    	int oil;
    }Status;
    
    int dir[4][3] = { {-1,0,0},{0,-1,0},{1,0,0},{0,1,0} };//←,↑,→,↓ 
    
    int main() {
    	int N = 0, K = 0, A = 0, B = 0, C = 0;
    	scanf("%d%d%d%d%d", &N, &K, &A, &B, &C);
    	dir[0][2] = dir[1][2] = B;//回退费用 
    	char map[105][105] = { 0 };
    	int mapOilFee[105][105][15];//一二维x, y, 第三维下标oil 值fee 记录较好状态下的油量与对应的费用 防止死循环
    	memset(mapOilFee, 0x3f, sizeof(mapOilFee));
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++) {
    			scanf("%d", &map[i][j]);
    		}
    	}
    
    	queue<Status> status;
    	int tx, ty, tfee;
    	int minFee = 0x3f3f3f3f;
    	Status t = { 1,1,0,K };
    	mapOilFee[1][1][K] = 0;//油量为K时fee==0
    	status.push(t);
    
    	while (status.size() != 0) {//BFS
    		t = status.front();
    		status.pop();
    		if (t.x == N && t.y == N)continue;
    		for (int i = 0; i < 4; i++) {
    			tx = t.x + dir[i][0];
    			ty = t.y + dir[i][1];
    			if (tx == N && ty == N) {//到达终点 
    				minFee = t.fee > minFee ? minFee : t.fee;
    				break;
    			}
    			if (tx<1 || tx>N || ty<1 || ty>N)continue;
    			Status tem = { tx,ty,0,t.oil - 1 };
    			tfee = t.fee + dir[i][2];//方向收费
    			if (map[tx][ty] == 1) {//加油站 
    				tfee += A;
    				tem.oil = K;
    			}
    			else if (t.oil == 1) {//半路没油 前面保证(tx,ty)没到终点 
    				tfee += C + A;
    				tem.oil = K;
    			}
    			tem.fee = tfee;
    			if (tfee < mapOilFee[tx][ty][tem.oil]) {
    				status.push(tem);
    				mapOilFee[tx][ty][tem.oil] = tfee;
    			}
    		}
    	}
    	printf("%d", minFee);
    	return 0;
    }
    

    BFS暴力搜索每个状态
    用队列优化空间复杂度
    判断一定得不到最优解的提前结束

    优化不够 会超时 会超时 会超时


    2019/4/24

  • 相关阅读:
    JavaScript学习总结【5】、JS DOM
    JavaScript学习总结【11】、JS 运动
    JavaScript学习总结【7】、JS RegExp
    JavaScript学习总结【1】、初识JS
    JavaScript学习总结【10】、DOM 事件
    直接选择排序及交换二个数据的实现
    快速排序
    Lucene.net搜索结果排序(单条件和多条件)
    冒泡排序
    直接插入排序的三种实现
  • 原文地址:https://www.cnblogs.com/kafm/p/12721814.html
Copyright © 2011-2022 走看看