题意
有(N)只骆驼过桥,桥可以分成(M)个部分,每个部分长(l_i),最大承重(v_i),骆驼的体重为(w_i),每只骆驼每秒速度为1个单位,所有骆驼排成一列过桥,一旦某段桥上的骆驼重量超过桥的承重,则桥会塌,如何安排骆驼的顺序以及相互间隔使骆驼平安过桥且第一只骆驼与最后一只骆驼的相互距离最短。
数据范围
[1leq N leq 8
]
[1leq M leq 10^5
]
[1leq w_i,l_i,v_ileq 10^8
]
思路
本题N的范围只有8,很显然这是暗示了N只骆驼的顺序是难以直接确定的,需要(O(N!))模拟,如果存在某种贪心策略或者神奇方法可以迅速确定N只骆驼的顺序,出题人肯定是会加大N的范围。
进一步分析,每次枚举骆驼的排列顺序枚举量为(8!=40320),就算我们对于M个桥段能一一检验也是会超时的。所以问题的关键在于对题目中桥的约束的理解。
对于一段长(l_i),承重为(v_i)的桥,我们可以发现只要存在一段骆驼之间的间距小于(l_i)且这些骆驼的重量大于(v_i)则桥一定会塌,否则一定能过这座桥。所以我们可以把一段桥的约束抽象为任意两个骆驼间的重量超过(v_i),则距离至少为(l_i)
这样抽象之后我们就不关心桥之间的顺序了,每一座桥就是一个约束条件,我们把每个约束按照(v_i)排序,这时约束间(l_i)应该是递增的,我们把一些无效的约束淘汰之后,剩下的约束(v_i,l_i)都是递增的,这时我们枚举任意两个骆驼,二分一个恰好的约束得到这两只骆驼之间的可能最近距离。动态规划即可得到最后一个骆驼到第一个骆驼的最小距离。
时间复杂度:(O(N!N^2log M+Mlog M))
代码
/*************************************************************************
> File Name: 1.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://blog.csdn.net/Pig_cfbsl
> Created Time: 2020/10/11 22:45:26
************************************************************************/
#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define pb push_back
#define pr pair<int,int>
#define fi first
#define se second
#define LL long long
#define mk(a,b) make_pair(a,b)
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=1e5+10;
int n,m,sum=0,cnt=0,mx,ans=1e9;
int w[10],tmp[10],s[10],dis[10],v[maxx],l[maxx];
int p[10]={0,1,2,3,4,5,6,7,8};
pr a[maxx];
bool cmp(pr x,pr y){
if(x.fi!=y.fi) return x.fi<y.fi;
return x.se>y.se;
}
int iso(int x){
x=lower_bound(v+1,v+cnt+1,x)-v-1;
return l[x];
}
int solve(){
s[0]=0;
For(i,1,n){ tmp[i]=w[p[i]]; s[i]=s[i-1]+tmp[i]; dis[i]=0;}
For(i,2,n) For(j,1,i-1){
dis[i]=max(dis[i],dis[j]+iso(s[i]-s[j-1]));
if(dis[i]>=ans) return dis[i];
}
return dis[n];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int u1,u2;
n=read(); m=read();
For(i,1,n){ w[i]=read(); mx=max(w[i],mx);}
For(i,1,m){
u1=read(); u2=read();
a[i]=mk(u2,u1);
if(u2<mx){ printf("-1
"); return 0; }
}
sort(a+1,a+m+1,cmp);
v[++cnt]=a[1].fi; l[cnt]=a[1].se;
For(i,2,m)
if(a[i].se>l[cnt]){
v[++cnt]=a[i].fi;
l[cnt]=a[i].se;
}
do{
ans=min(ans,solve());
}while(next_permutation(p+1,p+n+1));
printf("%d
",ans);
return 0;
}