传送门UVa 301 & HDU 1456 & POJ 1040 - Transportation
当大家看到这篇文章的时候,楼主已经差不多吐血身亡了。
下面是扯蛋部分,如果想直接看正文请跳过。。
---------------------------------------------------------------------------------------------------------
本来这题是昨天的任务,后来昨天有点累,便放到今天写。
早上八点开始。。直到下午三点半才AC。。。。说一下曲折经历,让大家乐乐。。
程序的主体部分在十点左右就写好了,自己想了几个数据,都对,于是满心欢喜地交了上去,痛快地WA了。
以为思路有问题,去找了一下解题报告,发现有和我思路一样的。证明总体思路没错,细节上有问题。
又看了几遍,实在看不出来,后来把一组数据交换了位置,答案变了。高兴,找到了一处错,改了,满心欢喜地交上去,POJ, HDU,UVA,痛快地给了我3个WA。
吃完饭又看了几遍,又交了一次,又收获了N个WA。
由于肯定思路是对的,我就去找数据,当然没找到。忽然想到LRJ老师说过可以自己生成数据对拍。
然后我就写了一个程序,找了个AC的代码,自己拍数据。。。
拍第一次,找到一个不一样的答案。改了,痛快WA。
拍第二次,找到一个不一样的答案。改了。。终于。。。。
虽然这次浪费了很多时间,不过学到了对比数据的生成,感觉还是挺值的。不然不知道什么时候我才会去看那个内容,它本来是被我跳过的。。LRJ老师请原谅我。。。
---------------------------------------------------------------------------------------------------------------
题目刚开始看着有点复杂,说起来很简单。
题意是两个城市之间有N个汽车站,编号为0~N-1。
每个汽车站点都有订单,盈利是(终点-起点)* 人数。
对于去同一地点的订票,要么全部上车,要么全部拒绝。
给出车的容量,汽车站的个数,订单的数目,求最大盈利。
我的思路完全是模拟实际情况。
假设一辆车从始发站开始开,开到下一个站的时候判断是否超载,如果是就继续往前开,不停记录最大盈利。
注意,这题和之前的回溯有点不一样,不能开一个vis数组。
比如就一条线路,0,1,2,都各一个人,都可以顺利到达终点,这样只要判断一次就可以了
如果开了这么一个数组,就变成了全排列,第一次记录下max之后,变成了0,2,1,又来一次,实际上这种情况和第一种是完全一样的,然后还会再来,浪费很多很多时间。
所以直接一直往前选就可以了,这跟排列组合的C和A有点像。。
train就是想象中正在开的公交车。。。
下面是随机数据生成的程序。。相信比起我的代码,大家更喜欢这个东西。。
数据生成默认容量10人,站数<=7,订单数<=7,如果大家要改,改order和n就行。
由于刚接触,代码不是很漂亮,大家看下总体思路就OK。。。
1.数据生成器
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
int capa = 10, n = 7, order = 7, cnt = 1000, peo = 10;
double random()
{
return (double)rand() / RAND_MAX;
}
int random(int m)
{
return (int)(random() * (m - 1) + 0.5);
}
int main()
{
freopen("output.txt", "w", stdout);
srand(time(NULL));
int X, Y, Z, a, b;
for (int i = 0; i < cnt; i++)
{
Y = random(n) + 1;
Z = random(order) + 1;
printf("10 %d %d\n",Y, Z);
for (int j = 0; j < Z; j++)
{
a = random(Y);
do
{
b = random(Y) + 1;
} while (b <= a);
printf("%d %d %d\n", a, b, random(peo));
}
}
printf("0 0 0\n");
return 0;
}
2.代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct NODE
{
int start, target, numPeo;
int benefits;
int leftEarn;
};
struct TRAIN
{
int curPeo, curIn;
int out[100];
TRAIN()
{
curIn = curPeo = 0;
memset(out, 0, sizeof(out));
}
};
bool cmp(NODE a, NODE b)
{
if (a.start < b.start)
return true;
return false;
}
int n, maxIn, capa, k;
NODE node[100];
void DFS(int cur, TRAIN train);
int main()
{
//freopen("output.txt", "w", stdout);
//freopen("input.txt", "r", stdin);
int i, j, numOrder, tempn, a, b, c;
TRAIN iniTrain;
while (scanf("%d%d%d", &capa, &tempn, &numOrder) && capa)
{ // ↑这个变量个人感觉就是没用
k = 0;
maxIn = -1;
for (i = 0; i < numOrder; i++)
{
scanf("%d%d%d", &a, &b, &c);
if (c <= capa) //排除超出容量的
{
node[k].start = a, node[k].target = b, node[k].numPeo = c;
node[k].benefits = (b - a) * c;
node[k++].leftEarn = (b - a) * c;
}
}
sort(node, node + k, cmp); //按起点从小到大排序
for (i = k - 2; i >= 0; i--)
node[i].leftEarn += node[i + 1].leftEarn;
DFS(0, iniTrain);
printf("%d\n", maxIn);
}
return 0;
}
void DFS(int cur, TRAIN train)
{
int i, j;
if (train.curIn > maxIn)
maxIn = train.curIn;
for (; cur < k; cur++)
{
if (train.curIn + node[cur].leftEarn < maxIn)
return;
//剪枝,如果,就算把这站以后的站的收益全算上去也抵不过MAX,之后就不用考虑了。
TRAIN temp = train; //保存个快照
for (i = 0; i <= node[cur].start; i++) //如果在这站之前有下车的,下了
if (train.out[i])
train.curPeo -= train.out[i], train.out[i] = 0;
if (train.curPeo + node[cur].numPeo > capa) //超出容量,舍弃
{
train = temp; //回档
continue;
}
train.out[node[cur].target] += node[cur].numPeo; //记录下车站点的下车人数
train.curPeo += node[cur].numPeo;
train.curIn += node[cur].benefits;
DFS(cur + 1, train);
train = temp; //回档
}
}