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 
#include 
#include 
#include 
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 
#include 
#include 
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   
      fill(vec.begin(), vec.end(), val);
      
      // 或者
      int a[10];
      fill(a, a+10, 20);
      

你可能感兴趣的:(PAT(甲级),算法比赛相关)