个人学习记录,代码难免不尽人意。
There is a public bike service in Hangzhou City which provides great convenience to the tourists from all over the world. One may rent a bike at any station and return it to any other stations in the city.
The Public Bike Management Center (PBMC) keeps monitoring the real-time capacity of all the stations. A station is said to be in perfect condition if it is exactly half-full. If a station is full or empty, PBMC will collect or send bikes to adjust the condition of that station to perfect. And more, all the stations on the way will be adjusted as well.
When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.
Sample Input:
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
Sample Output:
3 0->2->3 0
一开始我只用了dijkstra,结果只得到了23分。
#include <cstdio>
#include<set>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
int cmax,n,sp,m;
const int maxn=510;
const int INF=1000000000;
int C[maxn];
int G[maxn][maxn];
int sent[maxn];
int take[maxn];
int d[maxn];
int pre[maxn];
bool visit[maxn];
void dijkstra(int st){fill(visit,visit+n+1,false);fill(d,d+n+1,INF);sent[st]=0;take[st]=0;d[st]=0;for(int i=0;i<=n;i++){int m=-1,min=INF;for(int j=0;j<=n;j++){if(!visit[j]&&d[j]<min){min=d[j];m=j;}}if(m==-1) return;visit[m]=true;for(int j=0;j<=n;j++){if(!visit[j]&&G[m][j]!=INF&&d[j]>d[m]+G[m][j]){d[j]=d[m]+G[m][j];
// cout << "m=" << m <<"C[j]=" << C[j] <<endl; if(cmax/2-C[j]==0){sent[j]=sent[m];take[j]=sent[m];}else if(cmax/2-C[j]<0){//需要拿走 sent[j]=sent[m];take[j]=take[m]+abs(cmax/2-C[j]);}else{//需要带来 sent[j]=max(0,(cmax/2-C[j])-take[m]);take[j]=max(0,take[m]-(cmax/2-C[j]));}pre[j]=m;}else if(!visit[j]&&G[m][j]!=INF&&d[j]==d[m]+G[m][j]){if(cmax/2-C[j]==0){if(sent[j]>sent[m]){sent[j]=sent[m];take[j]=take[m];pre[j]=m;}}else if(cmax/2-C[j]<0){//需要拿走 if(sent[j]>sent[m]){sent[j]=sent[m];take[j]=take[m]+abs(cmax/2-C[j]);pre[j]=m;}}else{//需要带来 if(sent[j]>max(0,(cmax/2-C[j])-take[m])){sent[j]=max(0,(cmax/2-C[j])-take[m]);take[j]=max(0,take[m]-(cmax/2-C[j]));pre[j]=m;}}}}}
}
void dfs(int num){if(pre[num]==num){printf("%d",num);return;}dfs(pre[num]);printf("->%d",num);
}
int main(){scanf("%d%d%d%d",&cmax,&n,&sp,&m);C[0]=0;pre[0]=0;for(int i=1;i<=n;i++){scanf("%d",&C[i]);}for(int i=0;i<=n;i++){for(int j=0;j<=n;j++){G[i][j]=INF;}}for(int i=1;i<=m;i++){int a,b,dis;scanf("%d%d%d",&a,&b,&dis);G[a][b]=dis;G[b][a]=dis;}dijkstra(0);
// for(int i=0;i<n+1;i++){
// printf("%d ",take[i]);
// }
// for(int i=0;i<n+1;i++){
// printf("%d ",sent[i]);
// }printf("%d ",sent[sp]);dfs(sp);printf(" %d\n",take[sp]);}
后来我看了答案才发现不能只使用dijkstra方法来做,因为路径不满足最优子结构,必须采用dijkstra和dfs的方法来做。
正确代码如下:
//1018 Public Bike Management(30 分)
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXV = 510;
const int INF = 1000000000;
int n, m, Cmax, Sp, numPath = 0, G[MAXV][MAXV], weight[MAXV];
int d[MAXV], minNeed = INF, minRemain = INF;//minNeed记录最少携带的数目,minRemain记录最少带回的数目
bool vis[MAXV] = { false };
vector<int>pre[MAXV];
vector<int>tempPath, path;
void Dijkstra(int s) {fill(d, d + MAXV, INF);d[s] = 0;for (int i = 0; i <= n; i++) {int u = -1, MIN = INF;for (int j = 0; j <= n; j++) {if (vis[j] == false && d[j] < MIN) {u = j;MIN = d[j];}}if (u == -1)return;vis[u] = true;for (int v = 0; v <= n; v++) {if (vis[v] == false && G[u][v] != INF) {if (d[u] + G[u][v] < d[v]) {d[v] = d[u] + G[u][v];pre[v].clear();pre[v].push_back(u);}else if (d[v] == d[u] + G[u][v])pre[v].push_back(u);}}}
}
void DFS(int v) {if (v == 0) {tempPath.push_back(v);//计算最短路径标尺int need = 0, remain = 0;for (int i = tempPath.size() - 1; i >= 0; i--) {int id = tempPath[i];if (weight[id] > 0) {//如果当前节点点权为正,说明需要收走自行车,收走数量为点权值remain += weight[id];}else {//如果点权为负,则从前面收走的remain中向该节点投放自行车if (remain > abs(weight[id]))remain -= abs(weight[id]);else {//如果不够投放,需要从PBMC携带need += abs(weight[id]) - remain;remain = 0;//当前持有的自行车全部用来补给}}}if (need < minNeed) {//最短路径相同,选择需要从PBMC带的最少的情况minNeed = need;minRemain = remain;path = tempPath;}else if (need == minNeed && remain < minRemain) {//need还相同,选择remain少的情况minRemain = remain;path = tempPath;}tempPath.pop_back();return;}tempPath.push_back(v);for (int i = 0; i < pre[v].size(); i++) {DFS(pre[v][i]);}tempPath.pop_back();
}
int main() {(void)scanf("%d %d %d %d", &Cmax, &n, &Sp, &m);int u, v;fill(G[0], G[0] + MAXV * MAXV, INF);for (int i = 1; i <= n; i++) {(void)scanf("%d", &weight[i]);weight[i] -= Cmax / 2;//点权减去容量的一半,计算距离prefect还差多少}for (int i = 0; i < m; i++) {(void)scanf("%d %d", &u, &v);(void)scanf("%d", &G[u][v]);G[v][u] = G[u][v];}Dijkstra(0);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;
}