一、树形dp(4)有线电视网

来源:互联网 发布:dean martin知乎 编辑:程序博客网 时间:2024/05/03 07:25
4、 有线电视网
源程序名 tele.???( pas, c, cpp)
可执行文件名 tele.exe
输入文件名 tele.in
输出文件名 tele.out
【问题描述】
某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树
状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的
内部节点。
从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播
的总费用等于传输信号的费用总和。
现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪
些用户提供信号而不给哪些用户提供信号。
写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能
多。
【输入】
输入文件的第一行包含两个用空格隔开的整数 N 和 M,其中 2≤N≤3000, 1≤M
≤N-1, N 为整个有线电视网的结点总数, M 为用户终端的数量。
第一个转播站即树的根结点编号为 1,其他的转播站编号为 2 到 N-M,用户终端编号
为 N-M+1 到 N。
接下来的 N-M 行每行表示—个转播站的数据,第 i+1 行表示第 i 个转播站的数据,其
格式如下:
K A1 C1 A2 C2 … Ak Ck
K 表示该转播站下接 K 个结点(转播站或用户) ,每个结点对应一对整数 A 与 C, A 表
示结点编号, C 表示从当前转播站传输信号到结点 A 的费用。最后一行依次表示所有用户
为观看比赛而准备支付的钱数。
【输出】
输出文件仅一行,包含一个整数,表示上述问题所要求的最大用户数。
【样例输入】

tele.in

5 3
2 2 2 5 3
2 3 2 4 3
3 4 2
【样例输出】
tele.out
2
【样例解释】
如下图所示,共有五个结点。结点①为根结点,即现场
直播站,②为一
个中转站,③④⑤为用户端,共 M 个,编号从 N-M+1 到 N,
他们为观看比
赛分别准备的钱数为 3、 4、 2,从结点①可以传送信号到结点
②,费用为 2,
也可以传送信号到结点⑤,费用为 3(第二行数据所示),从
结点②可以传输信号到结点③,费用为 2。也可传输信号到结
点④,费用为 3(第三行数据所示),如果要让所有用户(③④⑤)都能看上比赛,则信号
传输的总费用为:
2+3+2+3=10,大于用户愿意支付的总费用 3+4+2=9,有线电视网就亏本了,而只让③
④两个用户看比赛就不亏本了。



分析:

用动态规划求解。状态这样定义,设F[A, M]为A结点下支持M个用户所能得到的最大赢利。转移方程为:
F[A, M]=Max{F[B1, M1]+F[B2, M2]+…+F[Bk, Mk] | Bi是A的子结点,M1+M2+…+Mk=M}
可以考虑将多叉数转换成二叉树来做,也可以考虑动态地分配内存。这样,空间复杂度约为O(n),时间复杂度为O(n2)。


代码:

const
  oo = -30000;
  MAX = 3000;


var
  n,m : integer;
  tablica,temp,veza,cijena : array[0..MAX, 0..MAX] of integer;
  koliko,placa : array[0..MAX] of integer;


function korisnik(a : integer) : boolean;
begin
  if (a >= n-m) then korisnik := true else korisnik := false;
end;


function maxi(a, b, c : integer) : integer;
begin
  if ((a >= b) and (a >= c)) then maxi := a
  else if ((b >= a) and (b >= c)) then maxi := b
  else maxi := c;
end;


function dfs(cvor : integer) : integer;
var
  i,j,k,dokle,ndokle,novi : integer;
begin
  for i:=1 to m do
  begin
    tablica[cvor,i] := oo;
    temp[cvor,i] := oo;
  end;


  tablica[cvor,0] := 0;


  dokle := 0;


  for i:=0 to koliko[cvor]-1 do
  begin
    novi := veza[cvor,i];


    temp[cvor,0] := 0;


    if (korisnik(novi)) then
    begin
      inc(dokle);


      for j:=1 to dokle do
        temp[cvor,j] := maxi(tablica[cvor,j], temp[cvor,j], tablica[cvor,j-1] - cijena[cvor,i] + placa[novi]);
    end
    else
    begin
      ndokle := dfs(novi);


      inc(dokle, ndokle);


      for j:=1 to dokle do
        for k:=1 to ndokle do
          if (j-k >= 0) then
            temp[cvor,j] := maxi(tablica[cvor,j], temp[cvor,j], tablica[cvor,j-k] - cijena[cvor,i] + tablica[novi,k])
          else break;
    end;


    for j:=0 to dokle do
    begin
      tablica[cvor,j] := temp[cvor,j];
      temp[cvor,j] := oo;
    end;
  end;


  dfs := dokle;
end;


var
  f : text;
  i,j,rjesenje : integer;
begin
  assign(f, 'tele.in'); reset(f);
  read(f, n, m);
  for i:=0 to n-m-1 do
  begin
    read(f, koliko[i]);
    for j:=0 to koliko[i]-1 do
    begin
      read(f, veza[i,j], cijena[i,j]);
      dec(veza[i,j]);
    end;
  end;
  for i:=n-m to n-1 do
  begin
    koliko[i] := 0;
    read(f, placa[i]);
  end;
  close(f);


  dfs(0);
  rjesenje := m;
  while (tablica[0,rjesenje] < 0) do dec(rjesenje);


  assign(f, 'tele.out'); rewrite(f);
  writeln(f, rjesenje);
  close(f);
end.


0 0
原创粉丝点击