题目链接:nyoj543遥控器 或者nsoj5138遥控器
题目描述与生活中使用遥控器的境况基本一致,此处不再累述。
我的思路:
从x频道转到y频道有两种方法,取两者按键次数少者
转频道方法1、
直接按↑up键、↓down键(前提是该键可用),此时需比较从x频道到y频道按up与down按键次数。比如x = 1,y = 98这种情况显然就是按down时次数少。
转频道方法2、
x频道先跳转到中间频道z,再按↑up键、↓down键到y频道(把x跳到y的情况看成z==y),当然跳转需要 _键 及数字键有用,跳转到小于10的频道无需判断 _键(题目已知)。跳转时按键次数+up或down次数即为总按键次数。
先执行方法1,再从0~99循环方法2(即把0~99频道当成z),得出最小值即为所求。
改进:
发现每次都循环0~99显然是没必要的,比如x=23,y=52,先由方法1得到按键次数min(此处为29)
我们只需循环52-(min:29-3)~~52+(min:29-3) 即26~~78=52次即可,其中3是此处跳转到z时需要按键的次数,由于z<10时为1,为了简化问题复杂性干脆不减,即从y-min循环到y+min。循环需要一个辅助数组,比如当x=29, y=1时,min=28, 此时循环就是从73到29,注意是73->99->0->29的循环,故需要一个辅助数组维持循环。
代码如下:
#include <stdio.h> #define INF 100//表示不可到达 int ctrl[15]; int getDif(int i, int j) {//从i频道up down到j所需次数 int dif = INF; if (j > i) { if (ctrl[10]) dif = j-i; if (ctrl[11] && dif > 50) dif = i+100-j; } else if (j < i) { if (ctrl[11]) dif = i-j; if (ctrl[10] && dif > 50) dif = j+100-i; } else return 0; return dif; } int main() { int T, n[333], i, j; //初始化辅助数组 for (i = 0; i < 301; i++) n[i] = i%100; scanf("%d", &T); while(T--) { int min = INF, count; //ctrl数组存遥控器 for (i = 0; i < 3; i++) { for (j = 1; j < 4; j++) scanf("%d", &ctrl[i*3+j]); scanf("%d", &ctrl[10+i]); } scanf("%d", &ctrl[0]); //其中0-9为数字0-9,10为up,11为down,12为_ //按此格式输人方便后续操作 scanf("%d%d", &i, &j);//i 跳转到 j min = getDif(i,j);//直接up down int m = j+101+min; i = j+100-min;//循环的开始与结尾 if (min == INF) {//min == INF说明up down不可用 m = j+101; i = j+100;//故调整m,i使循环中只判断能否直接跳转到j } for (i; i < m; i++) { int k = n[i]; count = 0; if (k < 10) {//中转频道<10时 if (ctrl[k]) {//若该键有用 count++; count += getDif(k, j);//中转频道再up down } else count = INF;//该键无用 } else { if (ctrl[12]) {//_键有用 count++; int q = k; while (q) { if (ctrl[q%10]) count++; else count += INF; q /= 10; } count += getDif(k, j); } else count = INF; } if (count < min) min = count; } if (min >= 100) printf("-1\n"); else printf("%d\n", min); } return 0; }