A1018 Public Bike Management (DFS, 未完成)

原题:

题目大意:每个自行车车站的最大容量为一个偶数cmax,如果一个车站里面自行车的数量恰好为cmax / 2,那么称处于完美状态。如果一个车站容量是满的或者空的,控制中心(处于结点0处)就会携带或者从路上收集一定数量的自行车前往该车站,一路上会让所有的车站沿途都达到完美。现在给出cmax,车站的数量n,问题车站sp,m条边,还有距离,求最短路径。如果最短路径有多个,求能带的最少的自行车数目的那条。如果还是有很多条不同的路,那么就找一个从车站带回的自行车数目最少的(带回的时候是不调整的)~
分析:Dijkstra + DFS。如果只有Dijkstra是不可以的,因为minNeed和minBack在路径上的传递不满足最优子结构,不是简单的相加的过程,只有在所有路径都确定了之后才能区选择最小的need和最小的back

只有Dijkstra(两个点无法通过)

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include<stack>
#include<queue>
#include<sstream>
using namespace std;

/*
A1018 Public Bike Management (30 分)
这题由于回来时不会放车,所以不是求全局最优解,不能用Dijstra
*/
const int MaxN = 510;
const int Inf = 0x3fffffff;


int G[MaxN][MaxN];		//边
int V[MaxN] = { 0 };			//点权,每个点的自行车数
int N;		//the total number of stations. But you need to add PBMC which is named "0"
int Cmax;	// the maximum capacity of each station,
int Sp;		//the index of the problem station 
int M;		//the number of roads

//找以s为起点的最短路,返回s->e最短路的编号序列
vector<int> Dijkstra(int s, int e, vector<int> &bike) {
	vector<int> path(N + 1, -1);	//存储路线
	vector<bool>vis(N + 1);
	vector<int> tim(N + 1);
	fill(vis.begin(), vis.end(), false);
	fill(tim.begin(), tim.end(), Inf);
	fill(bike.begin(), bike.end(), 0);		//存储一路可以获得车子数,负数代表需要补充
	tim[s] = 0;

	for (int i = 0; i < N+1; i++) {
		//寻找tim[]最小的未访问的结点v
		int v = -1, MIN = Inf;
		for (int j = 0; j < N + 1; j++) {
			if (tim[j] < MIN && vis[j]==false)
			{
				v = j;
				MIN = tim[j];
			}
		}
		if (v == -1) {
			cout << "Not a connected Graph!\n";
			break;
		}

		//访问
		vis[v] = true;
		//以结点v为中继更新未访问结点tim[]和path[]
		for (int j = 0; j < N + 1; j++) {
			if (vis[j] == false && G[v][j] != Inf) {
				if (tim[j] > tim[v] + G[v][j]) {
					tim[j] = tim[v] + G[v][j];
					path[j] = v;
					bike[j] = bike[v] + V[j] - Cmax / 2;
				}
				else if (tim[j] == tim[v] + G[v][j]  ) {
					//时间相等,1、比较送出车子数;2、比较运回车子数
					if (abs(bike[j]) > abs(bike[v] + V[j] - Cmax / 2)) {
						path[j] = v;
						bike[j] = bike[v] + V[j] - Cmax / 2;
					}
				}
			}
		}
	}

	//s->e最短路的编号序列
	vector <int> S_path;
	stack<int> st;
	int poi = e;
	while (poi != -1) {
		st.push(poi);
		poi = path[poi];
	}
	while (!st.empty()) {
		S_path.push_back(st.top());
		st.pop();
	}

	return S_path;

}

int main() {
	//freopen("input.txt", "r", stdin);

	fill(G[0], G[0] + MaxN * MaxN, Inf);
	G[0][0] = 0;
	cin >> Cmax >> N >> Sp >> M;
	for (int i = 1; i <= N; i++)
		cin >> V[i];
	for (int i = 0; i < M; i++) {
		int a, b, t;
		cin >> a >> b >> t;
		G[a][b] = G[b][a] = t;
	}

	vector<int> bike(N + 1),S_path;	//bike存储一路可以获得车子数,负数代表需要补充
	S_path=Dijkstra(0, Sp, bike);

	//Output
	if (bike[Sp] >= 0) {
		cout << "0 0";
		for (int i = 1; i < S_path.size(); i++) {
			cout << "->" << S_path[i];
		}
		cout << " " << bike[Sp] << endl;
	}
	else {
		cout << abs(bike[Sp]) << " 0";
		for (int i = 1; i < S_path.size(); i++) {
			cout << "->" << S_path[i];
		}
		cout << " " << 0 << endl;
	}

	return 0;
}

DFS

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int inf = 99999999;
int cmax, n, sp, m;
int minNeed = inf, minBack = inf;
int e[510][510], dis[510], weight[510];
bool visit[510];

//pre[i]记录到i的所有最短时间的路径中,每一个的上一个结点
vector<int> pre[510], path, temppath;
void dfs(int v) {
	temppath.push_back(v);
	if (v == 0) {	//从Sp回到0
		int need = 0, back = 0;
		for (int i = temppath.size() - 1; i >= 0; i--) {
			int id = temppath[i];
			if (weight[id] > 0) {
				back += weight[id];
			}
			else {
				if (back > (0 - weight[id])) {
					back += weight[id];
				}
				else {
					need += ((0 - weight[id]) - back);
					back = 0;
				}
			}
		}
		if (need < minNeed) {
			minNeed = need;
			minBack = back;
			path = temppath;
		}
		else if (need == minNeed && back < minBack) {
			minBack = back;
			path = temppath;
		}
		temppath.pop_back();
		return;
	}

	for (int i = 0; i < pre[v].size(); i++)
		dfs(pre[v][i]);
	temppath.pop_back();
}
int main() {
	fill(e[0], e[0] + 510 * 510, inf);
	fill(dis, dis + 510, inf);
	scanf("%d%d%d%d", &cmax, &n, &sp, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &weight[i]);
		weight[i] = weight[i] - cmax / 2;
	}
	for (int i = 0; i < m; i++) {
		int a, b;
		scanf("%d%d", &a, &b);
		scanf("%d", &e[a][b]);
		e[b][a] = e[a][b];
	}
	//类似Dijkstra
	dis[0] = 0;
	for (int i = 0; i <= n; i++) {
		int u = -1, minn = inf;
		for (int j = 0; j <= n; j++) {
			if (visit[j] == false && dis[j] < minn) {
				u = j;
				minn = dis[j];
			}
		}
		if (u == -1) break;
		visit[u] = true;
		for (int v = 0; v <= n; v++) {
			if (visit[v] == false && e[u][v] != inf) {
				if (dis[v] > dis[u] + e[u][v]) {
					dis[v] = dis[u] + e[u][v];
					pre[v].clear();
					pre[v].push_back(u);
				}
				else if (dis[v] == dis[u] + e[u][v]) {
					pre[v].push_back(u);
				}
			}
		}
	}

	dfs(sp);
	printf("%d 0", minNeed);
	for (int i = path.size() - 2; i >= 0; i--)
		printf("->%d", path[i]);
	printf(" %d", minBack);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值