1.10关路灯
来源:互联网 发布:android开发想找php 编辑:程序博客网 时间:2024/04/27 16:18
1.10关路灯
源程序名 power.???(pas, c, cpp)
可执行文件名 power.exe
输入文件名 power.in
输出文件名 power.out
【问题描述】
某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少)。老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯。
为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电。他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯。开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大的一边,再回过头来关掉另一边的路灯,而事实并非如此,因为在关的过程中适当地调头有可能会更省一些。
现在已知老张走的速度为1m/s,每个路灯的位置(是一个整数,即距路线起点的距离,单位:m)、功率(W),老张关灯所用的时间很短而可以忽略不计。
请你为老张编一程序来安排关灯的顺序,使从老张开始关灯时刻算起所有灯消耗电最少(灯关掉后便不再消耗电了)。
【输入】
文件第一行是两个数字n(0<n<50,表示路灯的总数)和c(1<=c<=n老张所处位置的路灯号);
接下来n行,每行两个数据,表示第1盏到第n盏路灯的位置和功率。
【输出】
一个数据,即最少的功耗(单位:J,1J=1W·s)。
【样例】
power.in power.out
5 3 270 {此时关灯顺序为3 4 2 1 5,不必输出这个关灯顺序}
2 10
3 20
5 20
6 30
8 10
【算法分析】
设老张开始所在位置为c,以起始点c为分界点,算出左右两部分总的功率p_left和p_right,再来分别看向左与向右的情况。
向左走时,相应地可以减小左边应费的功,而增加右边应费的功,如果到一个点(一盏路灯处)所要时间为t,减少的功为(p_left+w[i])*t,增加的功为p_right*2t。
向右走时,相应地可以减小右边应费的功,而增加左边应费的功,如果到一个点(一盏路灯处)所要时间为t,减少的功为(p_righ+w[i])*t,增加的功为p_left*2t。
比较向左与向右的情况,找出比较好的一种确定方法。大部分情况能够解出最小值,但不能求出所有情况下最佳的解。
对于每一个所处位置,都可以选择向左或向右,不管是向左还是向右,相应耗电的变化都跟上面所述一样。所以可以选择回溯的算法来实现有限的搜索,对每一个点试探向左与向右的情况,在所有可能的情况中找出最优解。
【思考与提高】
上面的程序运算的范围很有限,当n比较大时就会栈溢出,如n>30时速度就比较慢了。实际情况调头的次数并不会多的,到底在什么时候掉头根据情况而定。我们可以从最后一步来思考:
最后一次关的可能是第一个灯也可能是最后一个灯,哪种情况所费的功小就选哪种;
最后一次关的是第一个灯的话,说明最后的方向是从最后到最前(右边到左边),最后倒数第二次的方向为从左到右,起点可能是原始起点(此时是第一趟),也可能是原始起点左边的点(此时至少是第二趟),一个个地试过去,先设拐一次弯,有可能拐的点都试过去,再试有两次拐弯换方向的情况,当再多的拐弯超过已有的解时就不要再向下试了。采用这种回溯方法,效率更高。
如果n再大一些,如到300以上,上述方法也有它的局限性,此时最好从动态规划法或贪心法的角度去思考。
上面是书上的题解
var f1,f2:text;n,i,j,c,ans,sum:longint;dx,a:array[0..50] of longint;b:array[0..50] of boolean;procedure f(w:longint);begin if w<ans then ans:=w;end;procedure find(x,p,w:longint);var k:longint;begin if w>=ans then exit; for k:=x-1 downto 1 do if not b[k] then begin b[k]:=true; if p-a[k]=0 then f(w+abs(dx[x]-dx[k])*p) else find(k,p-a[k],w+abs(dx[x]-dx[k])*p); b[k]:=false; break; end; for k:=x+1 to n do if not b[k] then begin b[k]:=true; if p-a[k]=0 then f(w+abs(dx[x]-dx[k])*p) else find(k,p-a[k],w+abs(dx[x]-dx[k])*p); b[k]:=false; break; end;end;begin assign(f1,'input.in'); assign(f2,'output.out'); reset(f1); rewrite(f2); readln(f1,n,c); for i:=1 to n do begin readln(f1,dx[i],a[i]); sum:=sum+a[i]; end; ans:=maxlongint; b[c]:=true; find(c,sum-a[c],0); writeln(f2,ans); close(f1); close(f2);end.
- 1.10关路灯
- 关路灯
- 关路灯
- wiki 1258 关路灯
- codevs 1258 关路灯
- 洛谷1220 关路灯
- 洛谷1220关路灯
- 洛谷P1220 关路灯
- CODEVS 1258 关路灯
- CODEVS 1258 关路灯
- codevs1258 关路灯
- 洛谷 P1220 关路灯
- 洛谷 P1220 关路灯
- 洛谷 P1220 关路灯
- 洛谷P1220 关路灯
- P1220 关路灯
- 洛谷 P1220 关路灯
- 洛谷 P1220 关路灯
- Windows Socket编程
- POJ3259 Wormholes 真尼玛坑爹!!!!!!
- PHP中用header("Location: test.php")进行跳转时应注意的问题
- websphere v7 下载
- IT行业在杭州 (搞笑版)
- 1.10关路灯
- 队列-----判断一个字符串是否是回文
- android 开发环境建立
- 继电器--单片机
- php页面跳转的几种实现方法
- 2.3例题--校门外的树--2808
- poj1011 sticks
- 关于openlayers的参数及其他
- 2.4例题--填词--2801