2017.07.09【NOIP提高组】模拟赛B组 购物 题解

原题:

https://jzoj.net/senior/#contest/show/2043/0

题目描述:

GDOI商场推出优惠活动,以超低价出售若干种商品。但是,商场为避免过分亏本,规定某些商品不能同时购买,而且每种超低价商品只能买一件。身为顾客的你想获得最大的实惠,也就是争取节省最多的钱。经过仔细研究,发现商场出售的超低价商品中,不存在以下情况:   
n(n>=3)种商品C1,C2,…..,Cn,其中Ci,Ci+1是不能同时购买的(i=1,2…,n-1)并且C1, Cn也不能同时购买。   
编程计算可以节省的最大金额数。

输入:

第一行两个整数K,M(1<=K<=1000).其中K表示超低价商品数。K种商品的编号依次为1,2,…,K。M表示不能同时购买的商品对数.接下来K行,第i行有一个整数Xi表示购买编号为i的商品可以节省的金额(1<=Xi<=100).再接下来M行,每行两个数A ,B,表示A和B不能同时购买,1<=A<=K,1<=B<=K,A<>B

输出:

仅一个整数,表示能节省的最大金额数。

样例输入:

3 1 1 1 1 1 2

样例输出:

2

分析:

经典的树形DP······

实现:

uses math;
var 
    p,t:array[1..1000,0..500]of longint;     
    c:array[1..1000]of longint;     
    v:array[1..1000]of boolean;     
    f:array[1..2,1..1000]of longint;     
    n,m,a,b,s,i:longint;
procedure make(x:longint);    
var 
    i:longint;    
begin 
    v[x]:=true; 
    for i:=1 to p[x,0] do       
        if not v[p[x,i]] then          
        begin 
            t[x,0]:=t[x,0]+1;          
            t[x,t[x,0]]:=p[x,i];          
            make(p[x,i]);          
        end;    
end; 
procedure dg(x:longint);    
var 
    i:longint;    
begin 
   
    if t[x,0]=0 then       
    begin       
        f[1,x]:=0;       
        f[2,x]:=c[x];       
        exit;       
    end; 
    for i:=1 to t[x,0] do dg(t[x,i]);    
    for i:=1 to t[x,0] do       
    begin 
      
        f[1,x]:=f[1,x]+max(f[1,t[x,i]],f[2,t[x,i]]);       
        f[2,x]:=f[2,x]+f[1,t[x,i]];       
    end; 
    f[2,x]:=f[2,x]+c[x];    
end; 
begin 
    readln(n,m); 
    for i:=1 to n do readln(c[i]); 
    for i:=1 to m do
    begin 
        readln(a,b); 
        p[a,0]:=p[a,0]+1;p[a,p[a,0]]:=b;    
        p[b,0]:=p[b,0]+1;p[b,p[b,0]]:=a;    
    end; 
    for i:=1 to n do 
        if p[i,0]=0 then s:=s+c[i]    
        else 
        if not v[i] then       
        begin       
            make(i);       
            dg(i); 
            s:=s+max(f[1,i],f[2,i]);       
        end; 
    writeln(s); 
end. 

你可能感兴趣的:(2017.07.09【NOIP提高组】模拟赛B组 购物 题解)