PAT AL 1018. Public Bike Management(有bug,待修复)(已找到,错误使用DP)

7 篇文章 0 订阅

奇怪的1018题的第7个case,怎么改都过不了。想不通,mark一下。代码见附A。此处用Dijkstra找最短路径的同时,更新从PBMC带去的自行车数和到达城市当前最优的路径(最短,带去和带回最少)。对了,此题需要注意的是,最短和带去车都相同时,还要比较带回的车数。


终于(3天后)找到了,这BUG。不能在Dijkstra同时更新自行车情况,带回的自行车不满足最优子结构性质。比如下面这个CASE:

最佳路径应该是0->2->3->4,但附A程序的答案显然会是0->1->3->4。

一个正确的解决办法是,将City中的pre换成pre[],记录每个到此的相同最短距离路径。然后才用DFS寻找带来带去车最少的路径,即将非DP部分分离出去。代码见附B。


附A:

#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

#define NO_ROAD	-1

int c, n, p, m;
int road[501][501];
int bike[501];
struct s_city{
	int send, back, time;
	int pre;
	bool visit;
}city[501];

void updateCity(int i, int s, bool force)
{
	int sb, bb;
	int halfc = c/2;
	if(bike[i] == halfc){
		sb = city[s].send;
		bb = city[s].back;
	}
	else if(bike[i] > halfc){
		sb = city[s].send;
		bb = bike[i]-halfc + city[s].back;
	}
	else{
		int diff = halfc - bike[i];
		if(diff <= city[s].back){
			sb = city[s].send;
			bb = city[s].back - diff;
		}
		else{
			sb = city[s].send + diff - city[s].back;
			bb = 0;
		}
	}
	if(force){
		city[i].send = sb;
		city[i].back = bb;
		city[i].pre = s;
	}
	else{
		if(sb < city[i].send || (sb==city[i].send && bb < city[i].back)){
			city[i].send = sb;
			city[i].back = bb;
			city[i].pre = s;
		}
	}
}

int main(void)
{
#ifdef DEBUG
	freopen("in.txt", "r", stdin);
#endif
	scanf("%d %d %d %d", &c, &n, &p, &m);
	int i, j;
	for(i=1; i<=n; ++i)
		scanf("%d", &bike[i]);
	for(i=0; i<=n; ++i){
		city[i].time = NO_ROAD;
		for(j=0; j<=n; ++j)
			road[i][j] = NO_ROAD;
	}
	for(i=0; i<m; ++i){
		int x, y, t;
		scanf("%d %d %d", &x, &y, &t);
		road[x][y] = road[y][x] = t;
	}

	// dijkstra
	int s = 0;
	// init
	city[s].visit = true;
	city[s].time = 0;
	while(s != p){
#ifdef DEBUG
		printf("start %d:\nsend back time pre visit\n", s);
#endif
		int minc = s;
		for(i=1; i<=n; ++i){
			if(city[i].visit) continue;
			// update city info
			if(road[s][i] != NO_ROAD){
				int tt = city[s].time + road[s][i];
				if(city[i].time==NO_ROAD || tt < city[i].time){
					city[i].time = tt;
					updateCity(i, s, true);
				}
				else if(tt == city[i].time){
					updateCity(i, s, false);
				}
			}
			// find next s(has the least time)
			if(city[i].time != NO_ROAD && (minc==s || city[i].time < city[minc].time))
				minc = i;
		}
#ifdef DEBUG
		for(j=0; j<=n; ++j)
			printf("%4d %4d %4d %4d %4d\n", city[j].send, city[j].back,\
					city[j].time, city[j].pre, city[j].visit);
#endif
		assert(minc != s);
		s = minc;
		city[s].visit = true;
	}

	// output
	printf("%d 0", city[p].send);
	int st[n], top=-1;
	for(i=p; i != 0; i=city[i].pre)
		st[++top] = i;
	while(top >= 0)
		printf("->%d", st[top--]);
	printf(" %d\n", city[p].back);

	return 0;
}

附录B:

#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
#include <assert.h>

#define NO_ROAD	-1

int c, n, p, m;
int road[501][501];
int bike[501];
struct s_city{
	int time;
	int pre[501], pcnt;
	bool visit;
}city[501];

int send, back;
int bestpath[501], cnt;

void calBike(int path[], int pos, int *psb, int *pbb)
{
	assert(pos>=0 && path[pos]==0);
	int halfc = c/2;
	*psb = *pbb = 0;
	for(--pos; pos>=0; --pos){
		int cur = path[pos];
		if(bike[cur] > halfc){
			*pbb += bike[cur]-halfc;
		}
		else if(bike[cur] < halfc){
			int diff = halfc - bike[cur];
			if(diff <= *pbb){
				*pbb -= diff;
			}
			else{
				*psb += diff - *pbb;
				*pbb = 0;
			}
		}
	}
#ifdef DEBUG
	printf("sb=%d, bb=%d\n", *psb, *pbb);
#endif
}

int main(void)
{
#ifdef DEBUG
	freopen("in.txt", "r", stdin);
#endif
	scanf("%d %d %d %d", &c, &n, &p, &m);
	int i, j;
	for(i=1; i<=n; ++i)
		scanf("%d", &bike[i]);
	for(i=0; i<=n; ++i){
		city[i].time = NO_ROAD;
		for(j=0; j<=n; ++j)
			road[i][j] = NO_ROAD;
	}
	for(i=0; i<m; ++i){
		int x, y, t;
		scanf("%d %d %d", &x, &y, &t);
		road[x][y] = road[y][x] = t;
	}

	// dijkstra
	int s = 0;
	// init
	city[s].visit = true;
	city[s].time = 0;
	while(s != p){
#ifdef DEBUG
		printf("start %d:\ntime pre visit\n", s);
#endif
		int minc = s;
		for(i=1; i<=n; ++i){
			if(city[i].visit) continue;
			// update city time and path
			if(road[s][i] != NO_ROAD){
				int tt = city[s].time + road[s][i];
				if(city[i].time==NO_ROAD || tt < city[i].time){
					city[i].time = tt;
					city[i].pre[0] = s;
					city[i].pcnt = 1;
				}
				else if(tt == city[i].time){
					city[i].pre[city[i].pcnt++] = s;
				}
			}
			// find next s(has the least time)
			if(city[i].time != NO_ROAD && (minc==s || city[i].time < city[minc].time))
				minc = i;
		}
#ifdef DEBUG
		for(j=0; j<=n; ++j){
			printf("%4d %4d %4d: ", city[j].time, city[j].pcnt, city[j].visit);
			for(i=0; i<city[j].pcnt; ++i)
				printf(" %d", city[j].pre[i]);
			printf("\n");
		}
#endif
		assert(minc != s);
		s = minc;
		city[s].visit = true;
	}

	// DFS
	int path[n], pt=-1;
	int sk[n], top=-1;		// index
	path[++pt] = p;
	sk[++top] = -1;
	send = back = INT_MAX;
	while(top >= 0){
		// next
		while(top >= 0 && (++sk[top]) == city[path[pt]].pcnt)
			--top, --pt;
		if(top < 0) break;

		int par = path[pt], ind = sk[top];
		path[++pt] = city[par].pre[ind];
		sk[++top] = -1;
		// one path
		if(path[pt] == 0){
#ifdef DEBUG
			for(i=pt; i>=0; --i)
				printf("%d:%d ", path[i], sk[i]);
			printf("\n");
#endif
			int sb, bb;
			calBike(path, pt, &sb, &bb);
			if(sb < send || (sb==send && bb < back)){
				send = sb;
				back = bb;
				for(i=0; i<=pt; ++i)
					bestpath[i] = path[pt-i];
				cnt = pt+1;
			}
		}
	}

	// output
	printf("%d 0", send);
	for(i=1; i < cnt; ++i)
		printf("->%d", bestpath[i]);
	printf(" %d\n", back);

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值