JZOJ 1154. 【GDOI2003】购物

来源:互联网 发布:淘宝店铺首页大图尺寸 编辑:程序博客网 时间:2024/05/29 19:54

1154. 【GDOI2003】购物 (Standard IO)

Time Limits: 1000 ms Memory Limits: 65536 KB

Description

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

Input

  第一行两个整数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

Output

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

Sample Input

3 1 1 1 1 1 2

Sample Output

2

Data Constraint

题解

把所有商品当成点,分两部分看

  1. 没有任何限制的点
  2. 有限制的点,相互限制的点连一条边

很明显,第一部分的点是一定要取的

而第二部分则构成了一棵树(因为没有环),这部分的点有两种解法

  1. 树形dp
    用f[i][0]表示不取第i个点
    用f[i][1]表示取第i个点
    转移就是老爸取了儿子不能取,儿子取了老爸不能取

  2. 二分图
    最优匹配问题,也可以转化为最小割
    求出来的最优匹配或最小割为ans
    则答案是n-ans/2

代码

树形dp

#include<cstdio>#include<algorithm>#define N 1001using namespace std;long map[N][N],father[N],lc[N],rb[N],ch[N];long f[N][2];void build(long now){   long i,next;    for(i=1;i<=map[now][0];i++)if(map[now][i]!=father[now]){        if(!lc[now])lc[now]=map[now][i];        else rb[next]=map[now][i];        father[map[now][i]]=now;        next=map[now][i];        ch[now]++;        build(next);    }}void suan(long now){   long q;    ch[father[now]]--;    if(!lc[now])        f[now][0]=0;    else for(q=lc[now];q;q=rb[q]){        f[now][0]+=max(f[q][0],f[q][1]);        f[now][1]+=f[q][0];    }}int main(){   long n,m,i,j,x,y,ans=0;    scanf("%ld%ld",&n,&m);    for(i=1;i<=n;i++)        scanf("%ld",&f[i][1]);    for(i=1;i<=m;i++){        scanf("%ld%ld",&x,&y);        map[x][++map[x][0]]=y;        map[y][++map[y][0]]=x;    }    for(i=1;i<=n;i++)        if(map[i][0]&&!father[i])            build(i);    for(i=1;i<=n;i++)if(!ch[i]){        suan(i);        for(j=father[i];!ch[j]&&j;j=father[j])            suan(j);    }    for(i=1;i<=n;i++)        if(!father[i])ans+=max(f[i][0],f[i][1]);    printf("%ld\n",ans);    return 0;}
原创粉丝点击