PC/UVa:110405/10026
一个鞋匠有n
个订单,一天只能处理一个订单,但是一个订单可能需要几天才能完成。对于第i
个订单,Ti
表示完成订单需要的时间,Si
表示开始这个订单之前,每天需要付的罚金。求一个订单的安排顺序,使得罚金最少。
这道题目虽然写出来了,但我不知道为什么是对的。
题目就是求所有订单的全排列,然后输出罚金最少的。因为订单数量特别大,搜索的话时间复杂度极高,下一步就想用DP。DP思路和之前写过的2.8.8 Yahtzee思路类似,可以去参考那个。但是DP的空间复杂度一样非常大,最多有2^1000
。
突然我就想出来一个办法,在输入已有的排列下,交换相邻的两个订单,并不会对这两个之外的订单产生额外的罚金(因为对于其它的订单,开始工作之前的天数都没变),所以罚金的变化就在这两个上。那么如果把这两个交换一下,罚金可能会变少,所以就一直交换相邻的两个,直到整个序列的罚金不再变小。
看了一眼输出结果,这么做是对的,不过不知道为什么。。。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int cases = 0;
cin >> cases;
for (int c = 0; c < cases; c++)
{
int n = 0, t, s;
cin >> n;
vector<int> viT, viS, viNum;
for (int i = 0; i < n; i++)
{
cin >> t;
cin >> s;
viT.push_back(t);
viS.push_back(s);
viNum.push_back(i);
}
while (1){
bool bSwap = false;
for (int i = 1; i < n; i++)
{
if (viT[viNum[i - 1]] * viS[viNum[i]] > viT[viNum[i]] * viS[viNum[i - 1]]){
viNum[i - 1] ^= viNum[i] ^= viNum[i - 1] ^= viNum[i];
bSwap = true;
}
}
if (!bSwap) break;
}
for (size_t idx = 0; idx < viNum.size() - 1; idx++)
{
cout << viNum[idx] + 1 << ' ';
}
cout << viNum.back() + 1 << endl;
if (c != cases - 1) cout << endl;
}
return 0;
}
/*
1
4
3 4
1 1000
2 2
5 5
*/