1018.Public Bike Management (30)

1018.Public Bike Management (30)

pat-al-1018

2017-02-02

  • 题意:找出耗时最短(单源最短路径)且send和back最少的路径
  • dijkstra加dfs
  • dfs中用了回溯法框架(其实我只学过回溯法,之前没有真的写过dfs……)
  • 关于send和back的计算稍微有点难理解,在草稿纸上写写
  • 对前驱节点使用了vector< int > pre来保存,因为可能不止一个,没法用数组
/**
 * pat-al-1018
 * 2017-02-01
 * Cpp version
 * Author: fengLian_s
 */
#include<cstdio>
#include<vector>
#include<cstring>
#define MAX 501
#define INF 0x3f3f3f3f
using namespace std;
vector<int> pre[MAX];
vector<int> path, tmpPath;
int D_valueOfBike[MAX];
int minSend = INF, minBack = INF;
void dfs(int s)
{
  if(s == 0)
  {
    tmpPath.push_back(s);
    int send = 0, back = 0;
    for(int i = tmpPath.size()-1;i >= 0;i--)
    {
      int id = tmpPath[i];
      if(D_valueOfBike[id] > 0)
        back += D_valueOfBike[id];
      else
      {
        if(back > (0 - D_valueOfBike[id]))
          back += D_valueOfBike[id];
        else
        {
          send += (0 - D_valueOfBike[id] - back);
          back = 0;
        }
      }
    }
    if(send < minSend)
    {
      minSend = send;
      minBack = back;
      path = tmpPath;
    }
    else if(send == minSend && back < minBack)
    {
      minBack = back;
      path = tmpPath;
    }
    tmpPath.pop_back();
    return;
  }
  else//回溯法
  {
    tmpPath.push_back(s);
    for(int i = 0;i < pre[s].size();i++)
      dfs(pre[s][i]);
    tmpPath.pop_back();
  }
}
int main()
{
  freopen("in.txt", "r", stdin);
  int maxC, n, s, m;
  int e[MAX][MAX], dist[MAX], visited[MAX];
  scanf("%d %d %d %d", &maxC, &n, &s, &m);
  for(int i = 1;i <= n;i++)
  {
    scanf("%d", &D_valueOfBike[i]);
    D_valueOfBike[i] -= maxC/2;
  }
  memset(e, 0x3f, sizeof(e));
  memset(dist, 0x3f, sizeof(dist));
  memset(visited, 0, sizeof(visited));
  for(int i = 0;i < m;i++)
  {
    int tmpS1, tmpS2, tmpTime;
    scanf("%d %d %d", &tmpS1, &tmpS2, &tmpTime);
    e[tmpS1][tmpS2] = tmpTime;
    e[tmpS2][tmpS1] = tmpTime;
  }
  //dijkstra:
  //printf("hello, dijkstra\n");
  dist[0] = 0;
  while(1)
  {
    int u, minD = INF;
    for(int i = 0;i <= n;i++)
    {
      if(visited[i] == 0 && dist[i] < minD)
      {
        minD = dist[i];
        u = i;
      }
    }
    visited[u] = 1;//别忘记写了
    if(minD == INF)
      break;
    for(int v = 0;v <= n;v++)
    {
      if(visited[v] == 0 && e[u][v] < INF)
      {
        //printf("e[%d][%d] = %d\n", u, v, e[u][v]);
        if(dist[v] > dist[u] + e[u][v])
        {
          dist[v] = dist[u] + e[u][v];
          pre[v].clear();
          pre[v].push_back(u);
        }
        else if(dist[v] == dist[u] + e[u][v])
        {
          pre[v].push_back(u);
        }
      }
    }
  }
  //dfs:
  dfs(s);
  //output:
  //test:
  // for(int i = 0;i < pre[s].size();i++)
  // {
  //   printf("%d\n", pre[s][i]);
  // }
  //test end
  printf("%d 0", minSend);
  for(int i = path.size()-2;i >= 0;i--)
  {
    printf("->%d", path[i]);
  }
  printf(" %d\n", minBack);
}

-FIN-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值