1018 Public Bike Management (30分)

这道题的难点在于如何求最少需要带来多少辆bike,需要最少带走多少辆bike。
注意: 在选定的最短路径各个节点中,每个节点必须都是perfect的。设PBMC为0号节点,如果第一个节点不是perfect,必须从PBMC中取,即带来。如果第一个节点bike数量充足,第二个节点不是perfect,可以用第一个节点中多余的bike来弥补第二个节点中bike的不足。以此类推。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int inf = 0x3fffffff;
const int maxn = 505;//the total number of stations;
int cmax, n, m, sp;
int bikeNum[maxn];
int Graph[maxn][maxn];
vector<int> pre[maxn];
bool vis[maxn] = {0};
int d[maxn];
vector<int >path, tempath;
int minNeed = inf, minRemain = inf;
void Dijkstra(int s)
{
fill(d, d+maxn, inf);
d[s] = 0;
for(int i=0;i<n+1;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+1;v++)
{
if(!vis[v] && d[u] + Graph[u][v] < d[v])
{
d[v] = Graph[u][v] + d[u];
pre[v].clear();
pre[v].push_back(u);
}
else if(!vis[v] && d[u] + Graph[u][v] == d[v]){
pre[v].push_back(u);
}
// if(!vis[v] && Graph[u][v] != inf)
// {
// if(d[u] + Graph[u][v] < d[v])
// {
// d[v] = Graph[u][v] + d[u];
// pre[v].clear();
// pre[v].push_back(u);
// }
// if(d[u] + Graph[u][v] == d[v]){
// pre[v].push_back(u);
// }
// }
}
}
}
void Dfs(int s)
{
if(s == 0)
{
tempath.push_back(s);
int need = 0, remain = 0;
int id;
for(int i=tempath.size()-2;i>=0;i--){//必须倒着遍历
id = bikeNum[tempath[i]];
if(id - cmax / 2 > 0) //需要带走
remain += (id - cmax / 2);
else if(id - cmax / 2 < 0) //需要弥补
{
int temp = cmax / 2 - id;
if(temp <= remain)
remain -= temp;
else{
need += (temp - remain);
remain = 0;
}
}
}
if(need < minNeed)//需要弥补
{
minNeed = need;
path = tempath;
minRemain = remain;
}
else if(need == minNeed && remain < minRemain)//需要带走
{
minNeed = need;
minRemain = remain;
path = tempath;
}
tempath.pop_back();
}
tempath.push_back(s);
for(int i=0;i<pre[s].size();i++)
Dfs(pre[s][i]);
tempath.pop_back();
}
int main()
{
std::ios::sync_with_stdio(false);
fill(Graph[0], Graph[0] + maxn*maxn, inf);
cin>>cmax>>n>>sp>>m;
for(int i=1;i<=n;i++)
cin>>bikeNum[i];
bikeNum[0] = 0;
int a, b, time;
for(int i=0;i<m;i++)
{
cin>>a>>b>>time;
Graph[a][b] = Graph[b][a] = time;
}
Dijkstra(0);
Dfs(sp);
cout<<minNeed<<" ";
for(int i=path.size() - 1;i>=0;i--)
{
cout<<path[i];
if(i != 0)
cout<<"->";
}
cout<<" ";
cout<<minRemain<<endl;
return 0;
}
在Dijkstra中,如果写成是:
for(int v=0;v<n+1;v++)
{
if(!vis[v] && Graph[u][v] != inf)
{
if(d[u] + Graph[u][v] < d[v])
{
d[v] = Graph[u][v] + d[u];
pre[v].clear();
pre[v].push_back(u);
}
if(d[u] + Graph[u][v] == d[v]){
pre[v].push_back(u);
}
}
}
则会超时,如果改为:
for(int v=0;v<n+1;v++)
{
if(!vis[v] && d[u] + Graph[u][v] < d[v])
{//加不加!vis[v]也无所谓。
d[v] = Graph[u][v] + d[u];
pre[v].clear();
pre[v].push_back(u);
}
else if(!vis[v] && d[u] + Graph[u][v] == d[v]){
pre[v].push_back(u);
}
}
}
就不会超时了。
注意:如果写第二种写法,const int inf = 0x3fffffff;
不能是0x7fffffff。因为如果是0x7fffffff的话,0x7fffffff+0x7fffffff则会溢出。
还要注意的是:如果用的cin、cout
的话,不关闭同步信号,也会超时。如果改为scanf、printf
输入输出,则不会超时。
在这道题中,我也测试了一下,用cin、cout
并且关闭同步信号,比scanf、printf
作为输入输出还要快,可以自己测试一下。
也即:
很多人会说cin
的速度比scanf
慢很多, 其实不然.
cin
慢的原因主要在于默认cin
与stdin
总是保持同步, 这一步是消耗时间大户.
只需要加上std::ios::sync_with_stdio(false)
来关闭同步就好了, 速度甚至要优于scanf.
下面是使用cin、cout
并且关闭同步的情况。
下面是使用scanf、printf
的情况。
测试了很多次,基本上就是这样。