不得不说,这题TLE让我A的好痛苦。。。
TLE的想法:首先想到的是回溯,和平常一样,枚举了所有情况,最关键的在于设了个标记数组vis, 记录每个路段是否被访问过,而且还是每次遍历从vis数组最开头遍历,遇到未访问的就再次选择并往下深搜。。 看似没什么大不了,可是TLE就出在这了!! 按这思路,变成了求全排列,也就是把顺序也考虑进去了(比如:最终答案是选择标号为 1、2、3、4的 可是在遍历的时候把1、2、3、4 1、3、2、4 1、4、2、3 2、3、1、4 ........A44种都遍历了!!!
AC代码: 也很粗糙,没考虑其他剪枝了。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Station {
int start, end;
int capacity;
} orders[23];
int m, n, maxEarnings, maxCap;
int sign[8]; //记录的是在这站的时候车上已经有多少乘客了.
/* 改变状态量 sign. */
void change(int i) {
int j;
for(j = orders[i].start; j < orders[i].end; j ++) {
sign[j] += orders[i].capacity;
}
}
/* 将状态量改回来. */
void anti_change(int i) {
int j;
for(j = orders[i].start; j < orders[i].end; j ++) {
sign[j] -= orders[i].capacity;
}
}
/* 判断能否选取. */
bool judge(int i) {
int j;
for(j = orders[i].start; j < orders[i].end; j ++) {
if(sign[j] + orders[i].capacity > maxCap) return false;
}
return true;
}
void dfs(int i, int earnings) {
int j;
if(earnings > maxEarnings)
maxEarnings = earnings;
/* 这里是从j = i + 1开始的, 因为之前的都已经尝试过了,
* 如果再往回去试探的访问,就会变成全排列的枚举,出现TLE的关键所在!
*/
for(j = i + 1; j < m; j ++) {
if(judge(j)) {
earnings += (orders[j].end - orders[j].start) * orders[j].capacity;
change(j);
dfs(j, earnings);
anti_change(j);
earnings -= (orders[j].end - orders[j].start) * orders[j].capacity;
}
}
}
int main()
{
int i;
while(scanf("%d%d%d", &maxCap, &n, &m) != EOF) {
if(maxCap == 0 && n == 0 && m == 0) break;
int start, end, people;
for(i = 0; i < m; i ++) {
scanf("%d%d%d",
&orders[i].start, &orders[i].end, &orders[i].capacity);
}
maxEarnings = 0;
memset(sign, 0, sizeof(sign));
dfs(-1, 0);
printf("%d\n", maxEarnings);
}
return 0;
}