Vijos 1048 送给圣诞夜的贺卡(dfs)

描述

每年的12月24日,是圣诞老人忙碌的日子,也只有这一天,他才会忙碌起来。面对着将要来临的宁静的夜晚,是一种怎样的幸福和安宁感。作为圣诞老人的第一件事,就是需要为世界各地的孩子们写上贺卡,带上自己的祝福和礼品送给他们。毕竟,世界上那么多可爱的孩子,要给他们每一个人写一封贺卡,单凭自己的力量是不足以完成的。
众所周知,一直陪伴在圣诞老人身边的是快乐的小精灵们。他们为圣诞老人而工作,其实是一个很乐意的事情。冰天雪地的北极,是他们的家,是圣诞老人的家。圣诞老人一直以来对于贺卡的书写非常重视,他也一直请一些优秀的小精灵们去帮助他完成这件事……
12月24日早上7点钟。北极圣诞区开了一个会,会议由圣诞老人主持,在会的其他都是小精灵们,他们似乎都非常高兴,原因是等待圣诞老人的一份名单。这份名单里面的人都是这些小精灵们,一共n有个小精灵。这n个小精灵是圣诞老人根据这一年大家的表现状况(比如说谁吃饭吃得最多、谁调制的巧克力最好吃、谁的笑声最大、谁最不喜欢哭等等因素)而制定的预选的书写贺卡者名单。
圣诞老人一个一个字,饱含激情地念出了每一个预选的小精灵。鼓掌……
可是,接下来。并不是这个预选名单里面的所有小精灵都可以参加贺卡书写这个合作性任务。因为在以前的贺卡书写合作任务中,有一些小精灵们因为某些原因而对书写的格式和书写的字体喋喋不休。所以尽量避免这种情况发生,圣诞老人必须从预选名单中选出m(1<=m<=n)个小精灵来完成这项任务。可是……每一个小精灵的贺卡书写质量又有所不同……
圣诞老人想了想,他觉得应该在其中选择m个小精灵,使得这m个小精灵中任意两个在曾经的贺卡书写合作任务中没有发生过矛盾冲突,并且需要这m个小精灵的书写质量的总合S最高。
格式

输入格式

第一行一个数n。
第二行n个数,第i个数代表预选名单中第i号小精灵的书写质量(均为非负整数)。
接下来有若干行,每行两个不同的非负整数x和y,表示预选名单中第x号和第y号的小精灵曾经在贺卡书写合作任务中发生过冲突。
输出格式

第一行一个数S。
样例1

样例输入1

3
4 2 5
1 2
Copy
样例输出1

9
Copy
限制

各个测试点1s
提示

1<=n<=50,1<=x,y<=n

思路:dfs+剪枝

题解:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
bool vis[500];
int sum[500];
bool pd[500][500];
int ans=0;
int n;
struct cc{
    int from,to;
}es[200000];//用邻接表存一定要开大,有冲突的对数不确定。
int first[200000],nxt[200000];
int tot=0;
void build(int ff,int tt)
{
    es[++tot]=(cc){ff,tt};
    nxt[tot]=first[ff];
    first[ff]=tot;
}
int val[500];
void dfs(int x,int now)
{
    if(now+sum[x]<=ans)//剪枝,如果后面的全用上也不如答案优直接减掉。 
    {
        return;
    }
    ans=max(ans,now);
    if(x>n)
    {
        return;
    }
    for(int i=0;i<=1;i++)
    {
        if(i==1)
        {
            for(int j=first[x];j;j=nxt[j]) //如果存在冲突就减掉 
            {
                int v=es[j].to;
                if((pd[x][v]&&vis[v]))
                {
                    return;
                }
            }
            vis[x]=1;
            dfs(x+1,now+val[x]);
            vis[x]=0;
        }
        else
        {
            dfs(x+1,now);
        }

    }
}
struct ff{
    int id,num;
}hhh[500];
int cmp(ff aa,ff bb)
{
    if(aa.num==bb.num)
    {
        return aa.id<bb.id;
    }
    return aa.num>bb.num;
}
int a[500];
int main()
{

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&hhh[i].num);
        hhh[i].id=i;
    }
    sort(hhh+1,hhh+n+1,cmp);//按价值从大到小排序,极大减少复杂度。 
    for(int i=1;i<=n;i++)
    {
        a[hhh[i].id]=i;
    }
    int x,y;
    while(scanf("%d%d",&x,&y)!=EOF)
    {
        x=a[x];
        y=a[y];
        build(x,y);
        build(y,x);
        pd[x][y]=1;
        pd[y][x]=1;
    }
    for(int i=1;i<=n;i++)
    {
        val[i]=hhh[i].num;
    }
    for(int i=n;i>=1;i--)
    {
        sum[i]=sum[i+1]+val[i];
    }
    dfs(1,0);
    printf("%d",ans); 
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值