0
点赞
收藏
分享

微信扫一扫

1018 Public Bike Management (30 分,附详细注释,逻辑分析)


写在前面

  • 实现思路
  • Dijkstra计算最短路径
  • 参数传递不满足最优子结构​​具体待研究​
  • DFS递归迭代计算最优解
  • 变量、函数相对较繁琐,涉及知识点较多​​研究ing​
  • 不会告诉你,​​一般博主不太懂的问题,都不怎么总结​

测试用例

input:
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
output:
3 0->2->3 0

ac代码

  • 参考算法笔记

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int maxv = 510;
const int inf = 1000000;

/* n顶点数,m边数,cmax最大容量,sp问题站点, G邻接矩阵,weight点权,d[]记录最短距离 */
int n,m,cmax,sp,numPath=0, G[maxv][maxv], weight[maxv];
/* minNeed最少携带数目,minRemain记录最少带回数目 */
int d[maxv], minNeed = inf, minRemain = inf;
bool vis[maxv] = {false};
vector<int> pre[maxv]; // 前驱
vector<int> tmpPath, path; // 临时路径及最优路径

void Dijkstra(int s) // s为起点
{
fill(d, d+maxv, inf);
d[s] = 0;
for(int i=0; i<n; i++) // 循环n次
{
int u=-1, mins = inf; // u使d[u]最小,min存放该最小d[u]
for(int j=0; j<=n; j++) // 找到未访问的顶点d[]最小的
{
if(vis[j] == false && d[j]<mins)
{
u = j;
mins = d[j];
}
}
// 找不到小于inf的d[u],说明剩下的顶点和起点s不连通
if(u==-1) return;

vis[u] = true; // 标记已经访问过
for(int v=0; v<=n; v++)
{
// v未访问, u能到达v
if(vis[v] == false && G[u][v] != inf)
{
if(d[u] +G[u][v] < d[v])
{
d[v] = d[u] + G[u][v]; // 优化d[v]
pre[v].clear();
pre[v].push_back(u);
}
else if(d[u] + G[u][v]==d[v]) pre[v].push_back(u);
}
}
}
}

void DFS(int v)
{
if(v==0) // 叶子节点
{
tmpPath.push_back(v);
int need = 0, remain = 0;
for(int i=tmpPath.size()-1; i>=0; i--)
{
int id = tmpPath[i];
if(weight[id]>0) // 点权大于0,说明需要带走一部分自行车
remain += weight[id];
else
{
if(remain > abs(weight[id])) remain -= abs(weight[id]);
else
{
need += abs(weight[id])-remain;
remain = 0;
}
}
}
if(need < minNeed) // 从PBMC携带自行车数目更少
{
minNeed = need;
minRemain = remain;
path = tmpPath;
}
else if(need == minNeed && remain < minRemain) // 携带数目相同,带回数目变少
{
minRemain = remain;
path = tmpPath;
}
tmpPath.pop_back();
return;
}
tmpPath.push_back(v);
for(int i=0; i<pre[v].size(); i++) DFS(pre[v][i]);

tmpPath.pop_back();
}

int main()
{
scanf("%d%d%d%d", &cmax,&n,&sp,&m);

int u, v;
fill(G[0], G[0]+maxv*maxv, inf); // 初始化图G
for(int i=1; i<=n; i++)
{
scanf("%d", &weight[i]);
weight[i] -= cmax/2; // 点权减去容量一半
}
for(int i=0; i<m; i++) // 存储图: 边、顶点
{
scanf("%d%d", &u, &v);
scanf("%d", &G[u][v]);
G[v][u] = G[u][v];
}

Dijkstra(0); // Dijkstra算法入口
DFS(sp);
printf("%d ", minNeed);
for(int i=path.size()-1; i>=0; i--)
{
printf("%d", path[i]);
if(i>0) printf("->");
}
printf(" %d", minRemain);
return 0;
}

学习代码

  • ​​解题思路一致​​,不再赘述

#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];
vector<int> pre[510], path, temppath;
void dfs(int v) {
temppath.push_back(v);
if(v == 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];
}
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;
}

知识点小结

  • 技能待更新
  • Dijkstra
  • dfs
  • tips
  • fill函数:将一个区间的元素都赋予val值
  • 函数参数:fill(vec.begin(), vec.end(), val); val为待替换的值
  • 代码示例

# include <algorithm>
fill(vec.begin(), vec.end(), val);

// 或者
int a[10];
fill(a, a+10, 20);


举报

相关推荐

0 条评论