青蛙过河(二分+并查集)

青蛙过河

来回x次,也就是从起点一共2x个青蛙走一遍到终点

用一个数组记录每次送多少个青蛙由i–>j

具体看acwing解析

#include 
#define ll long long

using namespace std;
typedef pair<int,int>PII;

const int N=1e5+10;
int n,m,L;
ll s[N];
int a[N],p[N],h[N];

int findFa(int x) {
	return x==p[x]?x:p[x]=findFa(p[x]);
}

int check(int mid) {

	for(int i=1; i<=n-1; i++)a[i]=h[i],p[i]=i;

	for(int i=1; i<=n; i++)s[i]=0;
	s[0]=m;//起点有2*x只青蛙
	for(int i=0; i<n; i++) {

		int j=i+mid;

		if(j>=n) { //一步直接到对岸
			s[n]+=s[i];
			s[i]=0;
		} else {
			while(1) {
				j=findFa(j);
				if(s[i]==0||j<=i)break;//当前i号位置不存在青蛙或者i到i+mid内没有石墩可以跳了
				//将x个青蛙由i运送到j
				ll x=min((ll)a[j],s[i]);
				s[j]+=x;
				a[j]-=x,s[i]-=x;
				//j位置石墩用完了,就向前找新的石墩
				if(a[j]==0)p[j]=findFa(j-1);
			}

		}
	}
	return s[n]==m;
}


int main() {

	cin>>n>>m;
	m*=2;

	for(int i=1; i<=n-1; i++) cin>>h[i];

	int l=1,r=n;
	//如果满足check应该找最大距离越小越好
	//如果不满足证明这个距离太小了应该放大 
	while(l<r) {
		int mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}

	cout<<r<<endl;






	return 0;
}

你可能感兴趣的:(二分查找,c++,算法,图论)