【HDU4313】 – Matrix – 樹狀DP Version 思路+解題報告+AC代碼【0.4%達成】

來源:互聯網
上載者:User
#include <cstring>#include <cstdlib>#include <cstdio>#include <algorithm>#include <iostream>using namespace std;/**    Problem: HDU4313 - Matrix - DP Version【0.4%達成】    Copyright : 歸我們學校集訓隊和本人所有,未經同意可以轉載。                【但是膽敢用於培訓的話,貴學校伺服器將經受本人長時間免費義務壓力測試,CC+TCP片段+類比訪問,至少1000 Zombies以上】                【請做好心理準備】    Thanks:感謝提供協助的 Dragon ,zjj , gzm , lqy , zsw,lpp等大神……            = =多謝你們的patient,排名不分先後。。。    Reference:——【凡是給出Reference的,底下的內容就是參考Reference和本人思路寫的,如有錯誤歡迎指正,如不希望本人引用請mail 0daydigger#gmail.com】            http://blog.csdn.net/cyberzhg/article/details/7790486   ——寫的很清晰的代碼,強烈推薦            http://page.renren.com/601081183/note/862977450 ——這個。。其實沒給dp怎麼寫。。。湊合看吧    Knowledge Point:鄰接表格儲存體,樹狀dp        傻逼錯誤:把<看成了>導致理解不能        傻逼錯誤II:媽的居然忘記了鄰接表格儲存體這個事兒!!    Thought:    首先,是關於那個奇怪的addEdge,好吧,圖論那章我還沒刷呢。    首先證明addEdge函數能正確的儲存圖的鄰接表。    鄰接表只儲存與節點i相鄰的節點資訊——這句話說給基礎不好的童鞋【就是你自己吧喂!    初始:        初始化的時候,head[]={-1},edge[]中沒有儲存東西,在第一對節點(u,v)被儲存的時候,        edge[v].next = head[u] == -1;        edge[u].next = head[v] == -1;        head[u] = v在edge[]中的下標        head[v] = u在edge[]中的下標        那麼從head[u]和head[v]開始遍曆的話,就能遍曆所有與u和v相鄰的節點。    保持:        對於(u',v'),如果(u',v')都是新節點的話,那麼在【初始】中已經證明了其正確性。        如果有一個不是新節點的話,設u'不是新節點。        那麼【u',v'指的是edge[]中儲存u',v'兩個點的下標,有時候也指節點本身,請按照上下文區分】        head[u']先被更新,指向儲存了v'資訊的edge[]的下標。        然後head[v']更新,儲存了指向u'資訊的edge[]的下標。        由於有一句話        edge[edgeNum].next = head[u']        ...        head[u'] =  edgeNum++        那麼edge[v']中保留的就是以前head[v']中的資訊,使得        for(i = head[u]; i != -1 ; i = head[u].next ) 就可以用edge[i]來遍曆u的鄰接表了。        如果兩個節點都是老節點的話,同理    終止        根據【保持】中的分析,得到(u,v)的時候,可以            addEdge(u,v,w);            addEdge(v,u,w);便可以使得圖中的每個點都建立起鄰接表了。    ——————————————————————接下來是dp部分的證明————————————————————    dp[][],第一個維度儲存節點,第二個維度只有2個大小    dp[u][0]表示當u為根的子樹(包含u哦,下同)中不含機器時【需要耗費多少時間】    dp[u][1]表示當u為根的子樹中含有一台機器的時候【需要耗費多少時間】    那麼,當u為葉子節點,且u有機器(即color[u] = BLACK)的時候:    dp[u][0] = INFINITE;    dp[u][1] = 0;    u是葉子節點,u不含有機器(color[u] = WHITE)的時候    dp[u][0] = 0;    dp[u][1] = INFINITE;    那麼,當u為非葉子節點的時候,對於【全部u的鄰接表中的節點v】(←這句話很重要!閱讀下文的時候請務必牢記!)採取以下策略:    ————————————————————嫌囉嗦就直接看最後一部分!——————————————    ①如果u有機器        那沒的說了,dp[u][0]這時候就廢了。只能用dp[u][1]了        dp[u][1] += min(dp[v][0],dp[v][1] + w);  //v是u的鄰接表中所有節點        這個方程的意思是說,因為u本身已經有機器了,那麼dp[u][1]只要選        dp[v][0]或者dp[v][1]+w就好,dp[v][1]+w是指把(u,v)這條邊減下去,選這倆小的就好。    ②如果u沒有機器        dp[u][0] += min(dp[v][0],dp[v][1]+w);        還是一樣,如果u沒有機器的話,那麼把dp[v][0]和dp[v][1]+w選一個小的就好,如果v有一個機器的話        只要刪了u與v連著的這條邊就可以了。        但是我們還要考慮dp[u][1]呢。        如果我們選擇了dp[v][0]:            此時只要在消耗的時間中【減去】【最大的】dp[v][1] - dp[v][0]就好            亦即 dp[u][1] = dp[u][0] + minEdge   (minEdge = dp[v][1] - dp[v][0],dp[v][1]一定比dp[v][0]要小,因為dp[v][0]要多剪掉一刀)            因為dp[v]中儲存的可都是節點v的最優狀態,我們從鄰接節點v中選出來一條權值最大的帶機器的邊的權值從dp[u][0]中減去            直接得到的就是dp[u][1]的最優解。        如果我們選擇了dp[v][1]+w            此時就是minEdge與 -w 比較,如果minEdge 比較大的話,minEdge = -w;        遍曆中開一個變數cnt記錄u的子樹個數,如果u>0的話,且u沒有機器那麼遍曆結束後:            dp[u][1] = dp[u][0] + minEdge( minEdge是負的 )        ————————————給嫌囉嗦的人看——————————        總之!anyway!我們就是要在節點u的所有後代v中找出來一條權值最大並且串連帶機器的點的邊(臥槽真尼瑪繞嘴)        從dp[u][0]中減去其權值,那麼直接就得到了dp[u][1]的最優解。        具體實現是用DFS實現的(總有種感覺裸搜也能過……)        Q.E.D.*/const int WHITE = 0;const int BLACK = 1;const int MAX_SIZE = 100005;const __int64 INFINITE = 100000000000LL;struct node{    __int64 v;    __int64 w;    int next;};__int64 dp[MAX_SIZE][2];node edge[MAX_SIZE*2];int head[MAX_SIZE];int edgeNum;char color[MAX_SIZE];void addEdge(int u,int v,int w){    edge[edgeNum].v = v;    edge[edgeNum].w = w;    edge[edgeNum].next = head[u];    head[u] = edgeNum++;}void dfs(int u,int father){    long long minEdge = INFINITE;    int cnt = 0;    int v = 0;    int w = 0;    if( color[u] == BLACK )  //has machine    {        dp[u][0] = INFINITE;        dp[u][1] = 0;    }    else    {        dp[u][0] = 0;        dp[u][1] = INFINITE;    }    for(int i = head[u]; i != -1 ; i = edge[i].next)    {        v = edge[i].v;        w = edge[i].w;        if( v != father )        {            dfs(v,u);            if( color[u] )            {                dp[u][1] += min(dp[v][0],dp[v][1] + w);            }            else            {                dp[u][0] += min(dp[v][0],dp[v][1] + w );                cnt++;                if ( dp[v][0] <= dp[v][1] + w)                {                    if( minEdge > dp[v][1] - dp[v][0] )                        minEdge = dp[v][1] - dp[v][0];                }                else                {                    if( minEdge > -w )                        minEdge = -w;                }            }        }    }    if( color[u] == WHITE  && cnt > 0 )        dp[u][1] = dp[u][0] + minEdge;}int main(){    int T;    int N,K;    int u,v,w;#ifndef ONLINE_JUDGE    freopen("B:\\acm\\SummerVacation\\DP-II\\C.in","r",stdin);    freopen("B:\\acm\\SummerVacation\\DP-II\\C.out","w",stdout);#endif    while(scanf("%d",&T) != EOF)    {        for(int t = 1 ; t <= T ; t++)        {            memset(head,-1,sizeof(head));            memset(color,0,sizeof(color));            edgeNum = 0;            memset(edge,0,sizeof(edge));            scanf("%d%d",&N,&K);            for(int i = 1 ; i < N ; i++)            {                scanf("%d%d%d",&u,&v,&w);                addEdge(u,v,w);                addEdge(v,u,w); //構造串連表            }            for(int i = 0 ; i < K ; i++)            {                scanf("%d",&u);                color[u] = BLACK;            }            dfs(0,-1);            if( color[0] == WHITE )            {                printf("%I64d\n",min(dp[0][0],dp[0][1]));            }            else            {                printf("%I64d\n",dp[0][1]);            }        }    }#ifndef ONLINE_JUDGE    fclose(stdin);    fclose(stdout);#endif    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.