题意:假设一个站点可容纳Capacity辆自行车(c确保为偶数),则恰有c/2辆时为完美状态。若某站点当前自行车数量为满,管理中心就会前往该站点进行回收;若当前数量为0,则管理中心就会向该站点派发自行车。需要注意的是,由管理中心到站点Sp沿路的所有站点在去的途中就会被调整至完美状态(“all the stations on the way will be adjusted as well.”)。当问题站点Sp发出调整请求后,管理中心会选择耗时最短的一条路径;若有多条最短路径,则选择需要派发车辆最少的那一条。若仍然有多条路径,则选择需要带回管理中心的自行车数量最少的路径。
思路:本题采用Dijkstra+DFS的思路来做。Dijkstra只负责求出最短路径,以及记录最短路径中结点的前驱。更新派发车辆send以及带回的车辆remain在DFS中完成。求最短路就不用赘述了,套模板,下面讲一下如何求最优解。
我们令send表示需要从PBMC发出的自行车数量,初始化为0。即沿途中若有站点的自行车数量小于c/2的,就需要从PBMC中派发,遍历过程中一直累加;令remain表示在处理当前站点i之前,处理完[1~i-1]个站点后余留下来的数量,其值要么为0,要么大于0,初始化也为0。每访问一个站点i时,考虑此前余留的数量remain+该站点的数量是否达到完美状态,即remain+bike[i]与c/2的大小关系,若remain+bike[i]<c/2,说明需要从管理中心额外再派发,因此send要累加,即send+=c/2-(remain+bike[i]),并同时更新remain=0(没得剩了嘛);若remain+bike[i]>=c/2时,说明处理完这个站点后,自行车数量还有的多(即若有需要,可以增补给后面的站点),因此更新remain=remain+bike[i]-c/2,send则不需要处理。
代码:
#include <cstdio> #include <vector> #include <algorithm> using namespace std; const int Inf=0x7fffffff; const int maxn=510; struct Node{ int v; int t; Node(int v_,int t_):v(v_),t(t_){} }; vector<Node> Adj[maxn]; vector<int> pre[maxn]; bool vis[maxn]; int mindis[maxn]; int bike[maxn]; int c,n,sp,m; void Dijkstra(int s) { fill(vis,vis+maxn,false); fill(mindis,mindis+maxn,Inf); mindis[s]=0; for(int k=0;k<=n;k++){ int u=-1,min=Inf; for(int v=0;v<=n;v++){ if(!vis[v] && mindis[v]<min){ min=mindis[v]; u=v; } } if(u==-1) return; vis[u]=true; //relax:松弛操作 for(auto node:Adj[u]){//u-v if(!vis[node.v]){ if(mindis[u]+node.t < mindis[node.v]){ mindis[node.v]=mindis[u]+node.t; pre[node.v].clear(); pre[node.v].push_back(u); }else if(mindis[u]+node.t == mindis[node.v]){ pre[node.v].push_back(u); } } } } } //打印路径 vector<int> path,tmp; int minSend=Inf, minRemain=Inf; void dfs(int v) { tmp.push_back(v); if(v==0){//起点固定为0 int perfect=c/2; int remain=0,send=0; for(auto it=tmp.rbegin()+1;it!=tmp.rend();it++){//路径中的首个结点是PBMC,它不参与计算 if(remain+bike[*it] < perfect){ send += perfect-(remain+bike[*it]); remain = 0; }else if(remain+bike[*it] >= perfect){ remain = remain+bike[*it]-perfect; } } if(send<minSend){ minSend=send; minRemain=remain; path=tmp; }else if(send==minSend && remain<minRemain){ minRemain=remain; path=tmp; } return; } for(auto p:pre[v]){ dfs(p); tmp.pop_back(); } } int main() { //freopen("pat.txt","r",stdin); scanf("%d%d%d%d",&c,&n,&sp,&m); for(int i=1;i<=n;i++) scanf("%d",&bike[i]); int u,v,t; for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&t); Adj[u].push_back(Node(v,t)); Adj[v].push_back(Node(u,t)); } Dijkstra(0); dfs(sp); printf("%d ",minSend); for(int i=path.size()-1;i>=0;i--){ printf("%d",path[i]); if(i>0) printf("->"); } printf(" %d\n",minRemain); return 0; }