奇怪的1018题的第7个case,怎么改都过不了。想不通,mark一下。代码见附A。此处用Dijkstra找最短路径的同时,更新从PBMC带去的自行车数和到达城市当前最优的路径(最短,带去和带回最少)。对了,此题需要注意的是,最短和带去车都相同时,还要比较带回的车数。
终于(3天后)找到了,这BUG。不能在Dijkstra同时更新自行车情况,带回的自行车不满足最优子结构性质。比如下面这个CASE:
最佳路径应该是0->2->3->4,但附A程序的答案显然会是0->1->3->4。
一个正确的解决办法是,将City中的pre换成pre[],记录每个到此的相同最短距离路径。然后才用DFS寻找带来带去车最少的路径,即将非DP部分分离出去。代码见附B。
附A:
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#define NO_ROAD -1
int c, n, p, m;
int road[501][501];
int bike[501];
struct s_city{
int send, back, time;
int pre;
bool visit;
}city[501];
void updateCity(int i, int s, bool force)
{
int sb, bb;
int halfc = c/2;
if(bike[i] == halfc){
sb = city[s].send;
bb = city[s].back;
}
else if(bike[i] > halfc){
sb = city[s].send;
bb = bike[i]-halfc + city[s].back;
}
else{
int diff = halfc - bike[i];
if(diff <= city[s].back){
sb = city[s].send;
bb = city[s].back - diff;
}
else{
sb = city[s].send + diff - city[s].back;
bb = 0;
}
}
if(force){
city[i].send = sb;
city[i].back = bb;
city[i].pre = s;
}
else{
if(sb < city[i].send || (sb==city[i].send && bb < city[i].back)){
city[i].send = sb;
city[i].back = bb;
city[i].pre = s;
}
}
}
int main(void)
{
#ifdef DEBUG
freopen("in.txt", "r", stdin);
#endif
scanf("%d %d %d %d", &c, &n, &p, &m);
int i, j;
for(i=1; i<=n; ++i)
scanf("%d", &bike[i]);
for(i=0; i<=n; ++i){
city[i].time = NO_ROAD;
for(j=0; j<=n; ++j)
road[i][j] = NO_ROAD;
}
for(i=0; i<m; ++i){
int x, y, t;
scanf("%d %d %d", &x, &y, &t);
road[x][y] = road[y][x] = t;
}
// dijkstra
int s = 0;
// init
city[s].visit = true;
city[s].time = 0;
while(s != p){
#ifdef DEBUG
printf("start %d:\nsend back time pre visit\n", s);
#endif
int minc = s;
for(i=1; i<=n; ++i){
if(city[i].visit) continue;
// update city info
if(road[s][i] != NO_ROAD){
int tt = city[s].time + road[s][i];
if(city[i].time==NO_ROAD || tt < city[i].time){
city[i].time = tt;
updateCity(i, s, true);
}
else if(tt == city[i].time){
updateCity(i, s, false);
}
}
// find next s(has the least time)
if(city[i].time != NO_ROAD && (minc==s || city[i].time < city[minc].time))
minc = i;
}
#ifdef DEBUG
for(j=0; j<=n; ++j)
printf("%4d %4d %4d %4d %4d\n", city[j].send, city[j].back,\
city[j].time, city[j].pre, city[j].visit);
#endif
assert(minc != s);
s = minc;
city[s].visit = true;
}
// output
printf("%d 0", city[p].send);
int st[n], top=-1;
for(i=p; i != 0; i=city[i].pre)
st[++top] = i;
while(top >= 0)
printf("->%d", st[top--]);
printf(" %d\n", city[p].back);
return 0;
}
附录B:
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
#include <assert.h>
#define NO_ROAD -1
int c, n, p, m;
int road[501][501];
int bike[501];
struct s_city{
int time;
int pre[501], pcnt;
bool visit;
}city[501];
int send, back;
int bestpath[501], cnt;
void calBike(int path[], int pos, int *psb, int *pbb)
{
assert(pos>=0 && path[pos]==0);
int halfc = c/2;
*psb = *pbb = 0;
for(--pos; pos>=0; --pos){
int cur = path[pos];
if(bike[cur] > halfc){
*pbb += bike[cur]-halfc;
}
else if(bike[cur] < halfc){
int diff = halfc - bike[cur];
if(diff <= *pbb){
*pbb -= diff;
}
else{
*psb += diff - *pbb;
*pbb = 0;
}
}
}
#ifdef DEBUG
printf("sb=%d, bb=%d\n", *psb, *pbb);
#endif
}
int main(void)
{
#ifdef DEBUG
freopen("in.txt", "r", stdin);
#endif
scanf("%d %d %d %d", &c, &n, &p, &m);
int i, j;
for(i=1; i<=n; ++i)
scanf("%d", &bike[i]);
for(i=0; i<=n; ++i){
city[i].time = NO_ROAD;
for(j=0; j<=n; ++j)
road[i][j] = NO_ROAD;
}
for(i=0; i<m; ++i){
int x, y, t;
scanf("%d %d %d", &x, &y, &t);
road[x][y] = road[y][x] = t;
}
// dijkstra
int s = 0;
// init
city[s].visit = true;
city[s].time = 0;
while(s != p){
#ifdef DEBUG
printf("start %d:\ntime pre visit\n", s);
#endif
int minc = s;
for(i=1; i<=n; ++i){
if(city[i].visit) continue;
// update city time and path
if(road[s][i] != NO_ROAD){
int tt = city[s].time + road[s][i];
if(city[i].time==NO_ROAD || tt < city[i].time){
city[i].time = tt;
city[i].pre[0] = s;
city[i].pcnt = 1;
}
else if(tt == city[i].time){
city[i].pre[city[i].pcnt++] = s;
}
}
// find next s(has the least time)
if(city[i].time != NO_ROAD && (minc==s || city[i].time < city[minc].time))
minc = i;
}
#ifdef DEBUG
for(j=0; j<=n; ++j){
printf("%4d %4d %4d: ", city[j].time, city[j].pcnt, city[j].visit);
for(i=0; i<city[j].pcnt; ++i)
printf(" %d", city[j].pre[i]);
printf("\n");
}
#endif
assert(minc != s);
s = minc;
city[s].visit = true;
}
// DFS
int path[n], pt=-1;
int sk[n], top=-1; // index
path[++pt] = p;
sk[++top] = -1;
send = back = INT_MAX;
while(top >= 0){
// next
while(top >= 0 && (++sk[top]) == city[path[pt]].pcnt)
--top, --pt;
if(top < 0) break;
int par = path[pt], ind = sk[top];
path[++pt] = city[par].pre[ind];
sk[++top] = -1;
// one path
if(path[pt] == 0){
#ifdef DEBUG
for(i=pt; i>=0; --i)
printf("%d:%d ", path[i], sk[i]);
printf("\n");
#endif
int sb, bb;
calBike(path, pt, &sb, &bb);
if(sb < send || (sb==send && bb < back)){
send = sb;
back = bb;
for(i=0; i<=pt; ++i)
bestpath[i] = path[pt-i];
cnt = pt+1;
}
}
}
// output
printf("%d 0", send);
for(i=1; i < cnt; ++i)
printf("->%d", bestpath[i]);
printf(" %d\n", back);
return 0;
}