关路灯 与 MM不哭(TYVJ1097)

 关路灯     

源程序名            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

============

搜索

---------

优化

 1.只用搜到左边第一个或者右边第一个就是了...

============

var
  n,c,ans,total:longint;
  dis,w:array[0..60]of longint;
  f:array[0..60]of boolean;
  
procedure init;
begin
  assign(input,'power.in');
  assign(output,'power.out');
  reset(input);
  rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

procedure dfs(t,tot,total,t1:longint);
var
  i:longint;
begin
  for i:=t-1 downto 1 do
    if f[i] then
      begin
        if tot+(dis[t]-dis[i])*(total-w[t])<ans then
          begin
            f[i]:=false;
            dfs(i,tot+(dis[t]-dis[i])*(total-w[t]),total-w[t],t1+1);
            f[i]:=true;
            break;
          end;
      end;
  for i:=t+1 to n do
    if f[i] then
      begin
        if tot+(dis[i]-dis[t])*(total-w[t])<ans then
          begin
            f[i]:=false;
            dfs(i,tot+(dis[i]-dis[t])*(total-w[t]),total-w[t],t1+1);
            f[i]:=true;
            break;
          end;
      end;
  if t1=n then
    if tot<ans then
      begin
        ans:=tot;
        exit;
      end;
end;

procedure main;
var
  i:longint;
begin
  readln(n,c);
  total:=0;
  for i:=1 to n do
    begin
      readln(dis[i],w[i]);
      f[i]:=true;
      total:=total+w[i];
    end;
  ans:=maxlongint;
  f[c]:=false;
  dfs(c,0,total,1);
  writeln(ans);
end;

begin
  init;
  main;
  terminate;
end.

=====================================================================================================================================

 

 

 MM不哭

  
  描述 Description  
 在一个数轴上,有n个MM(绝非恐龙!)在哭泣(5555~一直哭).

tcboy也在这个数轴上,并恰好看到了这一幕,由于每个MM哭都会让tcboy损失一定的rp,于是tcboy有必要去安慰她们.(真命苦啊 T.T)

开始时,tcboy站在k号MM的旁边.

现在知道第i个MM哭泣每秒钟会使tcboy降低 w[i]的rp (单位rp/s).

而tcboy的行走速度很慢只有1m/s .

tcboy安慰MM的方式很特别(怎么安慰随便大家YY了..#@$%^%$#@),不需要花费时间.

请计算tcboy安慰完所有MM,会消耗掉的rp的最小值.
   
   
 输入格式 Input Format 
 输入文件的第一行包含一个整数N,2<=N<=1000,表示MM的数量。
第二行包含一个整数V,1<=V<=N,表示开始时tcboy站在几号MM的旁边.
接下来的N行中,每行包含两个用空格隔开的整数D和W,用来描述每个MM,其中0<=D<=1000,0<=W<=1000。D表示MM在数轴上的位置(单位: m),W表示每秒钟会使tcboy降低W的rp。
   
   
  输出格式 Output Format 
 输出只有一行:一个整数,即消耗rp之和的最小值。结果不超过1,000,000,000。

样例输入 Sample Input
4
3
2 2
5 8
6 1
8 7
     样例输出 Sample Output            56

==========================

这道题是上一道题的加强版

用上方的搜索只能过7个点

----------------------------------

稍微等一些日子做动规题时才来做..

----------------------

这东西拖得貌似比较久了,,于今日..NOIP2011的前一天才来完成的..

--

注意数组下标...

==========================

 

type
  node=record
         x,p:longint;
       end;
var
  n,v:longint;
  pi:array[0..1002]of node;
  f:array[1..1000,1..1000,0..1]of longint;
procedure init;
begin
  assign(input,'power.in');
  assign(output,'power.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

procedure qsort(s,t:longint);
var
  i,j:longint;
  x,tem:node;
begin
  x:=pi[(s+t)shr 1];
  i:=s; j:=t;
  repeat
    while x.x<pi[j].x do dec(j);
    while pi[i].x<x.x do inc(i);
    if i<=j then
      begin
        tem:=pi[i]; pi[i]:=pi[j]; pi[j]:=tem;
        inc(i); dec(j);
      end;
  until i>j;
  if i<t then qsort(i,t);
  if s<j then qsort(s,j);
end;

function min(a,b:longint):longint;
begin
  if a>b then exit(b);
  exit(a);
end;

procedure main;
var
  i,j:longint;
begin
  readln(n);
  readln(v);
  fillchar(pi,sizeof(pi),0);
  for i:=1 to n do
    readln(pi[i].x,pi[i].p);
  qsort(1,n);
  for i:=2 to n do pi[i].p:=pi[i-1].p+pi[i].p;
  fillchar(f,sizeof(f),$7);
  f[v,v,0]:=0; f[v,v,1]:=0;
  for i:=v downto 1 do
    for j:=v to n do
      if i<>j then
        begin
          f[i,j,0]:=min(f[i+1,j,0]+(pi[i].p+pi[n].p-pi[j].p)*(pi[i+1].x-pi[i].x),
                        f[i+1,j,1]+(pi[i].p+pi[n].p-pi[j].p)*(pi[j].x-pi[i].x));
          f[i,j,1]:=min(f[i,j-1,0]+(pi[i-1].p+pi[n].p-pi[j-1].p)*(pi[j].x-pi[i].x),
                        f[i,j-1,1]+(pi[i-1].p+pi[n].p-pi[j-1].p)*(pi[j].x-pi[j-1].x));
        end;
  writeln(min(f[1,n,0],f[1,n,1]));
end;

begin
  init;
  main;
  terminate;
end.


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值