HDU 1520 Anniversary party(樹形DP 數組和結構體鏈表兩種實現方式)

原題地址

Anniversary party

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9790 Accepted Submission(s): 4186


Problem Description
There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests' conviviality ratings.

Input
Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go T lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0

Output
Output should contain the maximal sum of guests' ratings.

Sample Input
7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0

Sample Output
5


這個的題目和前一篇,POJ2342是一模一樣的。但是把POJ的代碼往HDU上一交,TLE了。不得不說HDU的數據要比POJ狠一點。

看看POJ的題解:Click Me(・ω< )★

POJ那個時間寬裕,所以當時用的是雙親表示法,只記錄雙親節點。在尋找孩子節點的時候使用了遍歷,所以時間複雜度較高。
對於HDU這個題,這樣做就超時了。我們最好能用一個方法,既能快速尋找雙親,又能快速尋找孩子。

於是,我在POJ的代碼基礎上加了一個孩子列表。
嘛,差不多就是個戶口本吧。
用一個二維數組,一維是父母節點,另一維是他們的孩子:
     0  1  2
1 | 1  2  5
2 | 1  4
3 | 2  6  8
4 | 1  9
5 | 1  7
6 | 1  3
7 | 0
8 | 0
9 | 0
如上圖
child[ i ][ 0 ] = n表示 i 的孩子數目是n。
接下來的n個,child[ i ][ 1 ]……child[ i ][ n ]是她的孩子們。

這樣我們可以很方便的查詢他們的孩子節點,而避免因爲遍歷而超時。

AC代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int par[6066];//雙親節點
int child[6066][6066];//孩子列表(戶口本)
bool vis[6066];
int dp[6066][5];
int n;

void init(int n)
{
    for(int i=1; i<=n; i++)
    {
        par[i]=i;
        vis[i]=0;
        dp[i][1]=0;
        dp[i][0]=0;
        child[i][0]=0;
    }
}
void dfs(int root)
{
    vis[root]=1;
    for(int i=1; i<=child[root][0]; i++)//查詢孩子節點的時候可以直接用戶口本,而不用全抓來做親子鑑定
    {
        int son=child[root][i];
        if(!vis[son])
        {
            dfs(son);
            dp[root][1]+=dp[son][0];
            dp[root][0]+=max(dp[son][0],dp[son][1]);
        }
    }
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        init(n);
        int a,b;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&dp[i][1]);
        }
        while(scanf("%d%d",&a,&b))
        {
            if(a==0&&b==0)
            {
                break;
            }
            par[a]=b;
            child[b][0]++;//孩子數目加1
            child[b][child[b][0]]=a;//記錄孩子
        }
        int root=1;
        for(int i=1;i<=n;i++)
        {
            if(i==par[i])
            {
                root=i;
                break;
            }
        }
        dfs(root);
        printf("%d\n",max(dp[root][1],dp[root][0]));
    }
    return 0;
}

不過本人感覺這種方法實在遜爆了!這麼low,還浪費內存,用這樣low的代碼AC了就算不能表現出作爲一個ACMer的意志。

於是改用了結構體來儲存一個節點的父母,孩子,和兄弟節點的指針。

整個關係圖是用結構體鏈表來表示的。

這樣可以節省內存,並且結構上看起來更加簡潔明瞭。

struct nodes
{
    nodes *parent;
    nodes *child;
    nodes *borther;
    int val[5];
} node[6066];

如果一個節點有多個孩子是不容易表示的,我們不可能在一個節點上分配child1,child2……childn那麼多指針。天曉得他超生了多少個??

我的孩子的弟弟肯定也是我的孩子。所以我們只需要記錄下我的大兒子或者大女兒,然後詢問他的兄弟是誰就可以了。

                            brother             brother
             老爸   ————>二叔——————>三姑
parent ↑   ↓ child       brother                               brother                                       brother
              我 ————————>二妹———————————————>三妹————>我沒有弟弟妹妹了(NULL)
parent ↑   ↓ child                                                                                              ↑  ↓  brother
   大兒子——>小女兒——>再給我生個妹妹啦~(NULL)                      侄女————>我也想要妹妹……(NULL)
            brother          brother

PS:雖然很美好,但以上純屬YY……

那麼在本題中,老爸自然是直接上司,我的弟弟妹妹自然是同一個上司直接領導下的同事,兒女自然是直接下屬


AC代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct nodes
{
    nodes *parent;
    nodes *child;
    nodes *borther;
    int val[5];
} node[6066];

void dfs(nodes* root)
{
    nodes* p=root;
    if(p->child!=NULL)
    {
        p=p->child;
        dfs(p);
        root->val[1]+=p->val[0];
        root->val[0]+=max(p->val[0],p->val[1]);
        while(p->borther!=NULL)
        {
            p=p->borther;
            dfs(p);
            root->val[1]+=p->val[0];
            root->val[0]+=max(p->val[0],p->val[1]);
        }
    }
}

int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        int a,b;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&node[i].val[1]);
            node[i].borther=NULL;
            node[i].child=NULL;
            node[i].parent=NULL;
            node[i].val[0]=0;
        }
        while(scanf("%d%d",&a,&b))
        {
            if(a==0&&b==0)
            {
                break;
            }
            node[a].parent=&node[b];
            nodes *p=&node[b];
            if(p->child!=NULL)
            {
                p=p->child;
                while(p->borther!=NULL)
                {
                    p=p->borther;
                }
                p->borther=&node[a];
            }
            else
            {
                p->child=&node[a];
            }
        }
        nodes* root=&node[1];
        while(root->parent!=NULL)
        {
            root=root->parent;
        }
        dfs(root);
        printf("%d\n",max(root->val[1],root->val[0]));
    }
    return 0;
}





                                                                                                                                                                                     左:大女兒右:小女兒

                                                                                                                                                                                     反正沒人會看見,我就YY一下~23333

發佈了51 篇原創文章 · 獲贊 8 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章