UVa 301 & HDU 1456 & POJ 1040 - Transportation

本文详细记录了作者解决UVa301、HDU1456、POJ1040运输问题的过程。从程序主体快速完成到多次WA,再到通过数据生成发现问题并最终解决问题,文章不仅分享了解题技巧,还强调了对比数据生成的重要性。通过不断尝试和调整,作者最终找到了正确答案,学到了宝贵的编程经验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门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;	//回档
	}
		
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值