【问题描述】
有n个炸弹,有些炸弹牵了一根单向引线(也就是说引线只有在这一端能被炸弹点燃),只要引爆了这个炸弹,用引线连接的下一个炸弹也会爆炸。每个炸弹还有个得分,当这个炸弹被引爆后就能得到相应得分。
现在要你引爆k个炸弹,使得分最大。
【输入格式】
第1行两个整数n、k。
接下来n行每行两个整数a[i]、b[i]。a[i]表示这个炸弹用引线连接的下一个炸弹,如果a[i]为0,则表示这个炸弹没连接引线。b[i]表示这个炸弹的得分。
【输出格式】
仅一个数,表示最大得分
【输入样例】bomb.in
8 2
0 1
1 1
2 100
2 100
0 1
5 1
6 2
6 2
【输出样例】bomb.out
202
【数据规模】
1≤b[i]≤1000000
对于30%的数据,n≤1000 k≤30
对于60%的数据,n≤50000 k≤100
对于100%的数据,n≤200000 k≤500
/*
将每个点能引爆的最大价值求出
贪心
*/
#include<cstdio>
#include<cstring>
#include<fstream>
#define maxn 200010
using namespace std;
ifstream cin("bomp.in");
ofstream cout("bomp.out");
int n,k,o,i;
long long ans;
int x[maxn];
int value[maxn],num[maxn];
long long sum[maxn];
bool v[maxn];
void quicksort(int l,int r)
{
int i,j,z;
long long x,y;
i=l;j=r;
x=sum[(l+r)/2];
do
{
while (sum[i]>x) i++;
while (sum[j]<x) j--;
if (i<=j)
{
y=sum[i];
sum[i]=sum[j];
sum[j]=y;
z=num[i];
num[i]=num[j];
num[j]=z;
i++;j--;
}
}while (i<j);
if (i<r) quicksort(i,r);
if (l<j) quicksort(l,j);
}
int main()
{
//freopen("bomp.in","r",stdin);
//freopen("bomp.out","w",stdout);
//scanf("%d%d",&n,&k);
cin>>n>>k;
for (i=1;i<=n;i++)
{
//scanf("%d%d",&x[i],&value[i]);
cin>>x[i]>>value[i];
}
for (i=1;i<=n;i++)
{
int t;
t=x[i];
sum[i]=value[i];
while (t)
{
sum[i]+=value[t];
t=x[t];
}
}
for (i=1;i<=n;i++) num[i]=i;
quicksort(1,n);
memset(v,0,sizeof(v));
for (i=1;i<=n;i++)
{
int t=x[num[i]];
v[num[i]]=1;
while (t)
{
if (v[t])
sum[i]-=value[t];
v[t]=1;
t=x[t];
}
}
quicksort(1,n);
ans=0;
for (i=1;i<=k;i++) ans+=sum[i];
cout<<ans<<endl;
//printf("%lld\n",ans);
return 0;
}
浙公网安备 33010602011771号