【题目描述】
黑人学校开课了。黑人学校因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;
}