hdu4081 最小樹 DFS或者次小樹的變形

2021-06-20 20:18:31 字數 2647 閱讀 1900

題意:

給你乙個全圖,在裡面找到一棵樹,這棵樹最多只有一條邊可以不是最小樹(也可以是), 要求 那對特殊的邊的兩個權值/除了這條邊其他邊的和最大.

思路:方法有很多,最少有三種方法,我用兩種方法做的,別的暫時沒想到(太弱了);

第一種:

先求出來一顆最小樹,然後列舉樹上的邊,列舉到每一條邊的時候就假設把這條邊刪除了,然後分成兩個集合,我們只要在這兩個集合之間連一條邊,肯定就是樹了,那麼怎麼連呢,我們可以直接搜尋兩個集合中分別權值最大的那個點,假設連線這兩條邊,因為要就該邊的權值/非該邊的所有和最大,每次列舉相當於分母固定了(最小樹 - 當前列舉的邊),只要找到最大的分子就行了,所以在兩個集合裡面找最大的點.就這樣遍歷到最後,取得最大值就行了.

第二種:

第二種是和上面的想法相反的,是分子固定找分母,做法也是先找到一顆最小樹,然後列舉所有邊,當列舉該邊的時候就假設該邊就是那個特殊的邊,那麼權值分子就固定是邊的兩個點的權值,那麼分子呢,分兩種情況,如果當前列舉的邊不是最小樹上的邊,那麼加上這條邊後就一定會形成環,我們既然要比值最大,而且還必須是棵樹,那就必須在環上刪除一條最大的邊(不算當前這條邊),如果當前的邊是最小樹上的邊,那麼就刪除該邊就行了,其實兩種情況的寫法都一樣,分母都是 最小樹 - max(u ,v),max(u ,v)是樹上u,v,之間最長的邊,

可以在列舉前搜尋一遍求出來樹上任意兩點之間的最長邊(時間是o(n^2));就這樣遍歷到最後取最小就行了.....

我的兩個解法都跑了900多,原因是最小樹用的k求的,其實應該用p求會快很多,因為p是針對稠密圖的,後來的4756 用k就過不去,必須用p + 樹形dp 優化.

最小樹 + dfs

#include

#include

#include

#include

using namespace std;

typedef struct

node;

typedef struct

star;

typedef struct

edge;

node node[1100];

edge edge[1100 * 1100 /2];

star e[1100*2];

int list[1100] ,tot;

int mer[1100] ,max;

int mk[1100*2];

bool mark_dfs[1100];

int finds(int x)

void add(int a ,int b)

bool camp(edge a ,edge b)

void dfs(int s ,int w)

}int main ()

memset(list ,0 ,sizeof(list));

tot = 1;

double sum = 0;

sort(edge + 1 ,edge + tmp + 1 ,camp);

int mkt = 0;

for(i = 1 ;i <= n ;i ++)mer[i] = i;

for(i = 1 ;i <= tmp ;i ++)

double ans = 0;

for(i = 1 ;i <= mkt ;i ++)

printf("%.2lf\n" ,ans);

}return 0;

}有點像次小生成樹

#include

#include

#include

#include

#define n (1000 + 100)

using namespace std;

typedef struct

node;

typedef struct

edge;

typedef struct

star;

node node[n];

edge edge[n*n/2];

star e[n*2];

int list[n] ,tot;

int mark_dfs[n];

double maxe[n][n];

int mer[n];

void add(int a, int b ,double c)

int finds(int x)

bool camp(edge a ,edge b)

double maxx(double x ,double y)

void dfs_max(int s ,double nowmax ,int oo)

return;

}int main ()

sort(edge + 1 ,edge + tmp + 1 ,camp);

memset(list ,0 ,sizeof(list));

tot = 1;

double t_sum = 0;

for(i = 1 ;i <= n ;i ++) mer[i] = i;

for(i = 1 ;i <= tmp ;i ++)

for(i = 1 ;i <= n ;i ++)

double ans = 0;      

for(i = 1 ;i <= tmp ;i ++)

printf("%.2lf\n" ,ans);

}return 0;

}

hdu 4081 最小生成樹

先求出最小生成樹,然後列舉樹上的邊,對於每條邊 分別 找出這條割邊形成的兩個塊中點權最大的兩個 1.由於結果是a b,a的變化會引起b的變化,兩個制約,無法直接貪心出最大的a b,故要通過列舉 2.不管magic road要加在 加的邊是否是最小生成樹上的邊,都會產生環,我們都要選擇一條邊刪掉 注意...

hdu 4081 最小生成樹變形

關於最小生成樹的等效邊,就是講兩個相同的集合連線在一起 先建立乙個任意最小生成樹,這條邊分開的兩個子樹的節點最大的乙個和為a,sum為最小生成樹的權值和,b為sum 當前邊的權值 不斷列舉最小生成樹中的邊找最優值即可。include include include include define n ...

hdu 4081 次小生成樹

找到乙個生成樹,並且保證a b最大,所以b要盡量小,a盡量大。b盡量小,就要想到最小生成樹,但是最小生成樹裡面,可以刪除乙個邊,這樣就轉化為次小生成樹中找a b最大的情況。或者prim 並查集。include include include include include using namespa...