有N条绳子编号 0 至 N - 1,每条绳子后面栓了一个重物重量为Wi,绳子的最大负重为Ci。每条绳子或挂在别的绳子下或直接挂在钩子上(编号-1)。如果绳子下所有重物的重量大于绳子的最大负重就会断掉(等于不会断)。依次给出每条绳子的负重Ci、重物的重量Wi以及绳子会挂在之前的哪条绳子的下面,问最多挂多少个绳子而不会出现绳子断掉的情况。
例如下图:
5, 2, -1
3, 3, 0
6, 1, -1
3, 1, 0
3, 2, 3
挂到第4个时会有绳子断掉,所以输出3。
Input
第1行:1个数N,表示绳子的数量(1 <= N <= 50000)。 第2 - N + 1行:每行3个数,Ci, Wi, Pi,Ci表示最大负重,Wi表示重物的重量,Pi表示挂在哪个绳子上,如果直接挂在钩子上则Pi = -1(1 <= Ci <= 10^9,1 <= Wi <= 10^9,-1 <= Pi <= N - 2)。
Output
输出1个数,最多挂到第几个绳子,不会出现绳子断掉的情况。
Input示例
5 5 2 -1 3 3 0 6 1 -1 3 1 0 3 2 3
Output示例
3
一,直接思维:
从第一条绳子遍历,每次判断挂到第 i 条绳子时是否会断掉,判断是否断掉即,向上搜索它的连接绳子,判断所承载的重量是否大于它的最大承载即可。但当所有的绳子是连成一条直线时的最坏 时间复杂度是 O(n^2)
二, 二分:
可以对最多挂到的绳子数进行 二分查找。 而判断最多挂到第 k 条绳子时,可以从 第k条绳向前判断即可。这样的时间复杂度为 O(nlog(n))
三,并查集:
对于所有的绳子从最后一条开始计算,当计算到 第 k 条绳子的承载重量 s[k]>最大承载重量 a[k].Max时,则依次将最后一条绳子去掉,直到 s[k]<=a[k].Max为止,只要计算到第一条绳子时就可得到最多挂到第几个绳子。
Code 1:
//直接思维-最坏时间复杂度 O(n^2)
#include<iostream>
using namespace std;
const int MAX_N=50005;
struct node{
int c;
int w;
int pre;
}a[MAX_N];
int n,ans;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int d,w,k=0;
cin>>n;
for(int i=0;i<n;++i)
cin>>a[i].c>>a[i].w>>a[i].pre;
for(int i=0;i<n;++i)
{
if(a[i].w>a[i].c){
ans=i; k=0;
break;
}
d=a[i].pre; w=a[i].w;
while(d!=-1){
a[d].w+=w;
if(a[d].w>a[d].c){
k=1; ans=i; break;
}
d=a[d].pre;
}
if(k) break;
}
if(!k) ans=n;
cout<<ans<<endl;
return 0;
}
Code 2:
// 二分 O(nlog(n))
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
struct node{
int per;
int w;
int Max;
};
const int MAX_N=50005;
int n;
LL s[MAX_N]; //s[i]:第i条绳子下所有重物的重量
node a[MAX_N];
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=0;i<n;++i)
cin>>a[i].Max>>a[i].w>>a[i].per;
int l=0,r=n-1;
while(l<=r){
int h=(l+r)>>1;
bool boo=true;
memset(s,0,sizeof(s));
for(int k=h;k>=0;--k)
{
s[k]+=a[k].w;
if(s[k]>a[k].Max){
boo=false; break;
}
if(a[k].per!=-1) s[a[k].per]+=s[k];
}
if(boo==true){
l=h+1;
}else r=h-1;
}
cout<<r+1<<endl;
return 0;
}
Code 3:
//并查集 O(n)
#include<iostream>
using namespace std;
typedef long long LL;
struct node{
int per;
int w;
int Max;
};
const int MAX_N=50005;
int n;
int id[MAX_N];
LL s[MAX_N];
node a[MAX_N];
int Find(int k);
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=0;i<n;++i)
{
cin>>a[i].Max>>a[i].w>>a[i].per;
id[i]=i; s[i]=a[i].w;
}
int ans=n-1;
for(int i=n-1;i>=0;--i)
{
while(s[i]>a[i].Max){
s[Find(ans)]-=a[ans].w;
ans--;
}
s[a[i].per]+=s[i];
id[i]=a[i].per;
}
cout<<ans+1<<endl;
return 0;
}
int Find(int k)
{
if(k!=id[k]) id[k]=Find(id[k]);
return id[k];
}