【问题描述】
有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; }