題意:
給你乙個全圖,在裡面找到一棵樹,這棵樹最多只有一條邊可以不是最小樹(也可以是), 要求 那對特殊的邊的兩個權值/除了這條邊其他邊的和最大.
思路:方法有很多,最少有三種方法,我用兩種方法做的,別的暫時沒想到(太弱了);
第一種:
先求出來一顆最小樹,然後列舉樹上的邊,列舉到每一條邊的時候就假設把這條邊刪除了,然後分成兩個集合,我們只要在這兩個集合之間連一條邊,肯定就是樹了,那麼怎麼連呢,我們可以直接搜尋兩個集合中分別權值最大的那個點,假設連線這兩條邊,因為要就該邊的權值/非該邊的所有和最大,每次列舉相當於分母固定了(最小樹 - 當前列舉的邊),只要找到最大的分子就行了,所以在兩個集合裡面找最大的點.就這樣遍歷到最後,取得最大值就行了.
第二種:
第二種是和上面的想法相反的,是分子固定找分母,做法也是先找到一顆最小樹,然後列舉所有邊,當列舉該邊的時候就假設該邊就是那個特殊的邊,那麼權值分子就固定是邊的兩個點的權值,那麼分子呢,分兩種情況,如果當前列舉的邊不是最小樹上的邊,那麼加上這條邊後就一定會形成環,我們既然要比值最大,而且還必須是棵樹,那就必須在環上刪除一條最大的邊(不算當前這條邊),如果當前的邊是最小樹上的邊,那麼就刪除該邊就行了,其實兩種情況的寫法都一樣,分母都是 最小樹 - 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...