hdu3586 Information Disturbing(樹狀DP+二分查找)

一,題意

給定 n 個敵方據點,n 個點相連構成一棵樹,1 爲司令部,樹中每條邊都有一個權值 cost  表示破壞這條邊的費用。

葉子節點爲前線。現要切斷前線和司令部的聯繫,要求你截斷所有葉子節點的信息通過切斷樹中的一些邊。

每次切斷邊的費用不能超過上限 limit,切斷所有前線與司令部聯繫所花費的總費用要少於 m 要求最小的 limit。

二,解析:

該題主要應用了,樹狀DP的建樹與思想 + 二分查找。

1,數組dp:樹狀dp最重要的就兩點,一是:建樹,二是:遞推。

對於建樹,其實建立一個單項鍊表,該單項鍊表頭節點就是圖的節點,起後面連接的就是該節點所鄰接的邊(如圖)。


對於一般的數位dp思想是利用子節點的與父節點的關係來確定遞推關係。

2,該題能用到二分查找主要因爲兩點:一是收索的區間[low,tall]確定,二是因爲要求的是該區間的最值。

三,解析:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
const int Inf=1000010;
struct node
{//邊結構體
    int to,next,weight;
};
node Edge[2000];
int Size;
int head[1000];//節點數組
int N,M,total;
int mid;

void add(int from,int to,int weight)
{//向圖中插入一條邊
//這個建圖過程相當於單向鏈表的頭插法,head數組是各鏈表的頭節點
    Edge[Size].to=to;
    Edge[Size].weight=weight;
    Edge[Size].next=head[from];
    head[from]=Size++;
}

int DFS(int dan,int father)
{//由於每次邊的限制都不同所以DFS的路徑也不同所以不需要記錄狀態
//即使記錄了狀態也在後面也沒有用到。
    int res=0;//葉子節點邊界
    bool flog=false;
    for(int x=head[dan];x!=-1;x=Edge[x].next)
    {
        int to=Edge[x].to;
        if(to==father)
            continue;
        int total=DFS(to,dan);
        if(total>Edge[x].weight && Edge[x].weight<=mid)
            total=Edge[x].weight;
        res+=total;
        flog=true;
    }
    if(flog)
        return res;
    else
        return Inf;
}

int main()
{
    while(scanf("%d%d",&N,&M)!=EOF&&M)
    {
        int x,y,w;
        Size=0;
        int low=Inf,tall=-1;
        memset(head,-1,sizeof(head));
        for(int i=1;i<N;i++)
        {
            scanf("%d%d%d",&x,&y,&w);
            if(low>w)
                low=w;
            if(tall<w)
                tall=w;
            add(x,y,w);
            add(y,x,w);
        }
        int key=Inf;
        while(low<=tall)
        {//二分查找
            mid=(low+tall)/2;
            if(DFS(1,0)<=M)
            {
                key=mid;
                tall=mid-1;
            }
            else
                low=mid+1;
        }
        if(key!=Inf)
           cout<<key<<endl;
        else
            cout<<"-1"<<endl;
    }
    return 0;
}



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