黑吧反正不交税

【题目描述】

黑人学校开课了。黑人学校因CHY超强的黑人能力,决定在OI班里保送几位大神。已知OI班共有N名大神,学校计划最多保送M名大神,给出大神黑人能力值Ai。学校原计划按黑人能力排名录取,但大神之间有P对好友,必须一起录取他们,朋友的朋友当然是朋友啦。问黑人学校录取的大神的黑人能力之和最大是多少?若无法录取任何大神,则输出-1.

 

【输入格式】

第一行,M,N,P

第二行,N个数Ai-An

P+2行 两个整数 代表朋友信息 1 2表示1和2是朋友,必须同时报送

【输出格式】

一个正整数,答案或-1

 

【样例输入】

3 5 2

1 2 3 4 5

2 5

3 2

【样例输出】

10

【数据规模】

对于20%数据,N<=25,M<=25,P<=25;

对于100%数据,N<=5000,M<=5000,P<=4000,M<=N,P<=2N.


原题是Wikioi 2608


朋友的朋友是朋友 怎么办呢

1.并查集维护

2.BFS 将有关系的连在一起


然后以人数为重量 以能力为价值做01背包


话说01背包都不会写了!!!你个大弱B!!!


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int m,n,num;
int s[5055];
struct side{int x,y;}g[8044];
int first[8044],nxt[8044];

struct self{int w,v;}ss[5055];
int total,f[5055];

int a,b,c;

void push(int w,int v)
{
    total++;
    ss[total].w=w;ss[total].v=v;
}

bool relative[5055];
bool flag[5055];
int head,tail;
int q[5055];
void bfs(int i)
{
    head=tail=1;
    q[1]=i;
    flag[i]=1;
    while(head<=tail)
    {
        int u=q[head];
        for(int e=first[u];e!=-1;e=nxt[e])
        {
            if(!flag[g[e].y])
            {
                flag[g[e].y]=1;
                tail++;
                q[tail]=g[e].y;
            }
        }
        head++;
    }
    int v=0;
    for(int a=1;a<=tail;a++)v+=s[q[a]];
    push(tail,v);
}

bool luqu=0;

void pack()
{
    int l,r;
    for(l=1;l<=total;l++)
       for(r=n;r>=1;r--)
       {
            if(r>=ss[l].w&&f[r]<f[r-ss[l].w]+ss[l].v)
            {
                luqu=1;
                f[r]=f[r-ss[l].w]+ss[l].v;
            }
        }
    if(luqu)printf("%d\n",f[n]);
    else printf("-1\n");
}
    
int main()
{
    freopen("hei.in","r",stdin);freopen("hei.out","w",stdout);
    memset(first,-1,sizeof(first));
    memset(nxt,-1,sizeof(nxt));
    scanf("%d%d%d",&n,&m,&num); 
    for(a=1;a<=m;a++)scanf("%d",&s[a]);
    for(a=1;a<=num;a++)
    {
        scanf("%d%d",&g[a].x,&g[a].y);
        nxt[a]=first[g[a].x];first[g[a].x]=a;
        g[a+num].x=g[a].y;g[a+num].y=g[a].x;
        nxt[a+num]=first[g[a].y];first[g[a].y]=a+num;
        relative[g[a].x]=1;relative[g[a].y]=1;
    }
    for(a=1;a<=m;a++)
    if(!relative[a])push(1,s[a]);
    else
    if(!flag[a])bfs(a);
    pack();
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值