PAT 甲級 1018 Public Bike Management【Dijkstra+DFS】

求單源最短路,而且要求輸出路徑,非常完美的Dijkstra問題。
用Dijkstra求出多條路徑,再用DFS找到符合要求的路徑。(題目保證有唯一解)

一開始樣例5和7過不了,是因爲忽略了一個條件:後面的多餘的車子不能補充前面的。
我原來的算法是直接統計一條路上放出多少,收回多少直接抵消掉,這種算法就會導致後面的車子補充前面車子的情況出現。例如每個車站上限2量,現在路徑上車的數量是0→2,這種情況應該send一輛back一輛,而不是send零back零。

就因爲這一點思路上的不一樣,代碼就要大面積改動。。以後要仔細審題啊!
AC代碼:

//1018 dijkstra+dfs

int c,n,idx,m;
int station[505],road[505][505],v[505],d[505],minfa[505],maxfa[505],nowfa[505];

//保存重複路徑
vector<int> fa[505];

vector<int> pathh;
vector<int> ans;

//send表示要借出的車子,如果當前車站車子不夠先看手裏頭已經回收的車子夠不夠,不夠就只能從中心拿,不能取後面的
//backk表示回收的車子
int send,backk,minsend = 50010,minbackk = 50010;

void copy_s(){
    ans.clear();
    for(int i=0;i<pathh.size();i++)
        ans.push_back(pathh[i]);
}

//借車收車的路徑要正着計算
//但是保存的幾個最短路徑是倒着保存的,所以要藉助棧把順序正過來
//這裏用vector實現棧的功能,因爲複製函數比stack好寫。。。
void dfs(int i){
    if(i == 0){
        send=0,backk=0;
        for(int p=pathh.size()-1;p>=0;--p){
            if(station[pathh[p]] - c/2 >= 0) backk += (station[pathh[p]] - c/2);
            else{
                if(backk >= c/2-station[pathh[p]]) backk -=(c/2-station[pathh[p]]);
                else if(backk>0 && backk < (c/2 - station[pathh[p]]) ) {send += (c/2 - station[pathh[p]]-backk);backk = 0;}
                else if(backk == 0) send += (c/2 - station[pathh[p]]);
            }
        }
        //感覺下面這個判斷不是很嚴謹,但是題目保證了一定能有唯一解,所以能AC
        if(send<minsend){minsend = send;minbackk = backk;copy_s();}
        else if(send == minsend) {
            if(backk<minbackk) {minsend = send;minbackk = backk;copy_s();}
        }
        return;
    }

    for(int j=0;j<fa[i].size();j++){
        pathh.push_back(i);
        dfs(fa[i][j]);
        pathh.pop_back();
    }
}

void dijkstra(){
    //找到最短路徑
    memset(v,0,sizeof(v));
    for(int i=0;i<=n;i++) d[i] = (i==0 ? 0:INT_MAX);
    for(int i=0;i<=n;i++){
        int x,m = INT_MAX;
        //找到沒去過且距離最短的路
        for(int y=0;y<=n;y++) if(!v[y]&&d[y]<=m) m = d[x=y];
        v[x] = 1;
        //對於x出發的邊(x,y),更新d[y]
        for(int y=0;y<=n;y++) if(road[x][y]>0 && (d[y]>d[x]+road[x][y])){
            d[y] = d[x] + road[x][y];
            fa[y].clear();
            fa[y].push_back(x);
        }else if(road[x][y]>0 && (d[y]==d[x]+road[x][y])){
            //如果有到y點的重複路徑,添加前置結點
            fa[y].push_back(x);
        }
    }
    dfs(idx);
    printf("%d 0",minsend);
    for(int i=ans.size()-1;i>=0;--i) printf("->%d",ans[i]);
    printf(" %d",minbackk);
}


int main(){

    int x,y,z;

    scanf("%d%d%d%d",&c,&n,&idx,&m);
    memset(station,0,sizeof(station));
    memset(road,-1,sizeof(road));
    for(int i=1;i<=n;i++)
        scanf("%d",station+i);
    while(m--){
        scanf("%d%d%d",&x,&y,&z);
        road[x][y] = road[y][x] = z;
    }
    dijkstra();

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章