给定一个正整数,表示“ n”个人的穿越时间。这些“ n”个人站在桥的一侧。桥一次最多可容纳两个人。当两个人过桥时,他们必须以较慢的人的速度移动。找到所有人都可以过桥的最短总时间。看到这个难题以了解更多。
注意:较慢的人的步调是由较大的时间给出的。
Input: Crossing Times = {10, 20, 30}
Output: 60
Explanation
1. Firstly person '1' and '2' cross the bridge
with total time about 20 min(maximum of 10, 20)
2. Now the person '1' will come back with total
time of '10' minutes.
3. Lastly the person '1' and '3' cross the bridge
with total time about 30 minutes
Hence total time incurred in whole journey will be
20 + 10 + 30 = 60
Input: Crossing Times = [1, 2, 5, 8}
Output: 15
Explanation
See this for full explanation.
该方法是使用动态编程。在深入研究动态programminc之前,让我们看一下解决问题所需要的以下观察结果。
- 当任何两个人过桥时,最快的人过境时间将不会被回答,因为他们两个人的移动速度都是最慢的。
- 当一些人越过河流到达右侧时,只有最快的人(最小的整数)会回到左侧。
- 人员只能出现在桥的左侧或右侧。因此,如果我们保持左掩码,则可以通过将左掩码中不存在的位设置为“ 1”来轻松计算右掩码。例如,Right_mask =(((2 n )– 1)XOR(left_mask)。
- 任何人都可以很容易地用位掩码(通常称为“掩码”)表示。当设置“掩码”的第i个位时,这意味着该人位于桥的左侧,否则它将出现在桥的右侧。例如,假设6个人的掩码为100101,则代表人1、4、6位于桥的左侧,而人2、3和5位于桥的右侧。
// C++ program to find minimum time required to
// send people on other side of bridge
#include
using namespace std;
/* Global dp[2^20][2] array, in dp[i][j]--
'i' denotes mask in which 'set bits' denotes
total people standing at left side of bridge
and 'j' denotes the turn that represent on
which side we have to send people either
from left to right(0) or from right to
left(1) */
int dp[1 << 20][2];
/* Utility function to find total time required
to send people to other side of bridge */
int findMinTime(int leftmask, bool turn, int arr[], int& n)
{
// If all people has been transfered
if (!leftmask)
return 0;
int& res = dp[leftmask][turn];
// If we already have solved this subproblem,
// return the answer.
if (~res)
return res;
// Calculate mask of right side of people
int rightmask = ((1 << n) - 1) ^ leftmask;
/* if turn == 1 means currently people are at
right side, thus we need to transfer
people to the left side */
if (turn == 1) {
int minRow = INT_MAX, person;
for (int i = 0; i < n; ++i) {
// Select one people whose time is less
// among all others present at right
// side
if (rightmask & (1 << i)) {
if (minRow > arr[i]) {
person = i;
minRow = arr[i];
}
}
}
// Add that person to answer and recurse for next turn
// after initializing that person at left side
res = arr[person] + findMinTime(leftmask | (1 << person),
turn ^ 1, arr, n);
}
else {
// __builtin_popcount() is inbuilt gcc function
// which will count total set bits in 'leftmask'
if (__builtin_popcount(leftmask) == 1) {
for (int i = 0; i < n; ++i) {
// Since one person is present at left
// side, thus return that person only
if (leftmask & (1 << i)) {
res = arr[i];
break;
}
}
}
else {
// try for every pair of people by
// sending them to right side
// Initialize the result with maximum value
res = INT_MAX;
for (int i = 0; i < n; ++i) {
// If ith person is not present then
// skip the rest loop
if (!(leftmask & (1 << i)))
continue;
for (int j = i + 1; j < n; ++j) {
if (leftmask & (1 << j)) {
// Find maximum integer(slowest
// person's time)
int val = max(arr[i], arr[j]);
// Recurse for other people after un-setting
// the ith and jth bit of left-mask
val += findMinTime(leftmask ^ (1 << i) ^ (1 << j),
turn ^ 1, arr, n);
// Find minimum answer among
// all chosen values
res = min(res, val);
}
}
}
}
}
return res;
}
// Utility function to find minimum time
int findTime(int arr[], int n)
{
// Find the mask of 'n' peoples
int mask = (1 << n) - 1;
// Initialize all entries in dp as -1
memset(dp, -1, sizeof(dp));
return findMinTime(mask, 0, arr, n);
}
// Driver program
int main()
{
int arr[] = { 10, 20, 30 };
int n = sizeof(arr)/sizeof(arr[0]);
cout << findTime(arr, n);
return 0;
}
Output
60
时间复杂度:
辅助空间: