题目链接
题目描述
有n只骆驼过m桥,第i只骆驼负重(w_i),第i座桥的长度为(l_i),最大负重为(v_i),问骆驼队伍长度最短为多少可以通过所有的桥。
思路
n的数据范围很小,可以暴力解决。根据桥的长度从大到小预处理一下其能承受的重量。
(dp[i])表示从第一只骆驼到第i只骆驼的最短距离。
(dp[i] = max(dp[j] + len, dp[i])),len表示第j只骆驼到第i只骆驼的最短距离。寻找len的过程中就是在预处理的桥中二分一下第j只到第i只骆驼的重量所返回的最短桥的长度。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int LL
const int N = 1e5 + 10;
int w[10];
bool vis[10];
int b[10], s[10], dp[10];
struct node {
int l, v;
friend bool operator < (node a, node b) {
if(a.l == b.l) {
return a.v < b.v;
}
return a.l < b.l;
}
}a[N];
int n, m;
LL res;
int find(int x) {
int l = 1, r = m;
int res = 0;
while(l <= r) {
int mid = l + r >> 1;
if(x > a[mid].v) {
res = a[mid].l;
l = mid + 1;
} else r = mid - 1;
}
return res;
}
void work() {
memset(dp, 0, sizeof dp);
for(int i = 1; i <= n; i++) {
s[i] = s[i - 1] + w[b[i]];
}
for(int i = 2; i <= n; i++) {
for(int j = i - 1; j; j--) {
int tmp = s[i] - s[j - 1];
int len = find(tmp);
dp[i] = max(dp[i], dp[j] + len);
}
}
res = min(res, dp[n]);
}
void dfs(int cnt) {
if(cnt == n) {
work();
return;
}
for(int i = 1; i <= n; i++) {
if(!vis[i]) {
vis[i] = true;
b[cnt + 1] = i;
dfs(cnt + 1);
vis[i] = false;
}
}
}
void solve() {
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%lld", &w[i]);
}
for(int i = 1; i <= m; i++) {
scanf("%lld%lld", &a[i].l, &a[i].v);
}
sort(a + 1, a + 1 + m);
int mn = 1e9;
for(int i = m; i >= 1; i--) {
mn = min(mn, a[i].v);
a[i].v = mn;
}
for(int i = 1; i <= n; i++) {
if(mn < w[i]) {
puts("-1");
return;
}
}
res = 2e18;
dfs(0);
printf("%lld
", res);
}
signed main() {
// freopen("in.txt", "r", stdin);
// int t; scanf("%d", &t); while(t--)
solve();
}