Hdu 4267 the Ghost Blows Light

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4276)
參考鏈接:http://blog.csdn.net/u012841845/article/details/18739425
以及:http://blog.csdn.net/xianxingwuguan1/article/details/18954537
手寫(xiě)鄰接表:http://blog.csdn.net/ooooooooe/article/details/17035501

分析:先尋找1到N的最短路徑和走這段路所用的時(shí)間,再把路徑的權(quán)置為0,如果時(shí)間有多的,就把剩余的時(shí)間拿來(lái)進(jìn)行樹(shù)上背包,具體過(guò)程我已經(jīng)寫(xiě)在了程序的注釋里,之所以要寫(xiě)這個(gè),是因?yàn)榫W(wǎng)上關(guān)于這道題的文章雖然很多,但都講解得不是很清楚。
head數(shù)組是一種手寫(xiě)鄰接表的方法,在上面的網(wǎng)址可以找到,但是該博并沒(méi)有說(shuō)明,所以我特地去請(qǐng)教了另外的人。它是圖的另一種存儲(chǔ)方法,head[a]表示以a為起點(diǎn)的邊的編號(hào),下面的add函數(shù)中的head[u] = tol++是在更新編號(hào)(即改為當(dāng)前邊的編號(hào)),表面上看起來(lái)它是在一直變化,但是每一次add它都會(huì)把自己的指存儲(chǔ)在的edge結(jié)構(gòu)體中,這樣就可以根據(jù)一個(gè)head值一直找到它的父親的父親的父親......另外,之所以說(shuō)最短路上的邊指走一遍是因?yàn)樨?cái)寶只有那么多,拿了一次就沒(méi)有了。

include <cstdio>
include <cstring>
include <iostream>
using namespace std;

const int maxn = 200;  
int head[maxn], tol, dpmaxn, weight[maxn], T, t, n;

// 此結(jié)構(gòu)體表示各條邊(這里其實(shí)是把room當(dāng)做是有向無(wú)環(huán)圖來(lái)看待,  
// 每一條邊都以兩個(gè)方向來(lái)表示,該結(jié)構(gòu)體的元素含義如下:  
// next:表示下一條以當(dāng)前邊為起點(diǎn)的邊(和鄰接表的實(shí)現(xiàn)有些類(lèi)似) 
// to:表示這條邊的終點(diǎn)  
// time:表示走這條邊所需要的時(shí)間  
// 另外兩個(gè)就是默認(rèn)構(gòu)造函數(shù)和構(gòu)造函數(shù)了  
struct node  
{  
    int next, to, time;  
    node(){};  
    node(int next, int _to, int _time) : next(next), to(to), time(time){}  
}edge[5*maxn];

// add函數(shù)用來(lái)添加邊(每條邊用edge結(jié)構(gòu)體表示)  
void add(int u, int v, int time)  
{  
    edge[tol] = node(head[u], v, time);  
    head[u] = tol++;  
}

// 深度搜索找到1到N的最短路徑(即花費(fèi)時(shí)間最少)  
// 并把該路徑上的所有邊所要的時(shí)間置為0,方便之后搜索,并得到最短時(shí)間為t  
// 其中u表示當(dāng)前節(jié)點(diǎn),pre表示上一個(gè)節(jié)點(diǎn)  
bool dfs(int u, int pre)  
{  
    if(u == n)  
        return 1;  

    for(int i = head[u]; i != -1; i = edge[i].next)  
    {  
        int v = edge[i].to;  
        if( v == pre )  
            continue;  

        if(dfs(v, u)) // 當(dāng)返回1時(shí)就表示采取了那一條邊  
        {  
            t += edge[i].time;  
            edge[i].time = 0;  
            return 1;  
        }  
    }  
    return 0;
}

// 深度搜索,統(tǒng)計(jì)了所有節(jié)點(diǎn)在一定時(shí)間范圍內(nèi)所有時(shí)間所能獲得的最大價(jià)值  
// dpu:表示從u點(diǎn)出發(fā)到回到u點(diǎn),花費(fèi)時(shí)間j所能獲得的最大的財(cái)富  
void dfs1(int u, int pre)  
{  
    for(int i = 0; i <= T; i++) // T為剩下的總時(shí)間  
        dpu = weight[u]; // 只要是經(jīng)過(guò)了這個(gè)節(jié)點(diǎn)的都應(yīng)該把它的財(cái)寶即weight加起來(lái)  

    for(int i = head[u]; i != -1; i = edge[i].next) // 這就是上面使用鄰接表的作用,方便深度搜索  
    {  
        int v = edge[i].to;  
        if( v == pre ) // 如果是指向上一條邊的就直接略過(guò)  
            continue;  
        dfs1(v, u); // 遞歸       
        int pp = 2*edge[i].time; // 與u點(diǎn)直接相連的那一條邊的時(shí)間,因?yàn)槿绻^續(xù)下去,就必然會(huì)經(jīng)過(guò)該邊  
        for(int j = T; j >= pp; j–) // j必須大于走那條邊的時(shí)間,它表示的是從該邊走的總時(shí)間  
            for(int k = 0; k <= j-pp; k++) // k表示走了那條邊后從那條邊的終點(diǎn)繼續(xù)走所用的時(shí)間  
                dpu = max(dpu, dpv+dpu); // j-pp-k表示剩下的從u點(diǎn)出發(fā)走的時(shí)間  
    }  
}

int main()  
{  
    int i, j, k, p;  
    while(~scanf(“\%d\%d”, &n, &T))  
    {  
        memset(head, -1, sizeof(head));  
        tol = 0;  
        for(i = 1; i < n; i++)  
        {  
            scanf(“\%d\%d\%d”, &j, &k, &p);  
            add(j, k, p);  
            add(k, j, p);  
        }  
        for(i = 1; i <= n; i++)  
            scanf(“\%d”, &weight[i]);  
        t = 0;  
        dfs(1, 1);  
        if(t > T)  
        {  
            puts(“Human beings die in pursuit of wealth, and birds die in pursuit of food!”);  
            continue;  
        }  
        memset(dp, 0, sizeof(dp));  
        T -= t;  
        dfs1(1, -1);  
        cout<< dp1 <<endl; // 應(yīng)該無(wú)論是否從1出發(fā)都能得到同樣的結(jié)果的  
    }  
    return 0;  
}

這道題花了兩天時(shí)間,寫(xiě)了七八張紙都沒(méi)有完全理解清楚,難道真的是我太愚笨了嗎?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容