CodeForces 444A DZY Loves Physics
題目大意
給定一張無向圖,其中每個點有一個權值A u A_u A u ,每條邊有一個權值B u , v B_{u,v} B u , v ,要求找出一個子圖,使得子圖連通且任意兩點間存在邊則一定要被選中。
求出選出的子圖中點權之和除以邊權之和的最大值。
分析
結論: 這個子圖中僅包含一條邊和它的兩個端點。
然後就枚舉一條邊,計算它的答案。然後就完了。。。
證明: 我們只需要證明對於三個連成一條鏈的點u , v , w u,v,w u , v , w (u , w u,w u , w 是端點),選擇u , v , w u,v,w u , v , w 取不到最大值即可。
採用反證法:假設選擇了u , v , w u,v,w u , v , w 取得了最大值,那麼我們可以得到如下不等式:
{ A u + A v + A w B u , v + B v , w ≥ A u + A v B u , v A u + A v + A w B u , v + B v , w ≥ A w + A v B v , w
\begin{cases}\frac{A_u+A_v+A_w}{B_{u,v}+B_{v,w}}\ge \frac{A_u+A_v}{B_{u,v}}\\\frac{A_u+A_v+A_w}{B_{u,v}+B_{v,w}}\ge \frac{A_w+A_v}{B_{v,w}}\end{cases}
{ B u , v + B v , w A u + A v + A w ≥ B u , v A u + A v B u , v + B v , w A u + A v + A w ≥ B v , w A w + A v
簡單整理一下得到:
{ A w ≥ A v B u , v + A u B v , w B u , v A u ≥ A w B u , v + A v B u , v B v , w
\begin{cases}A_w\ge \frac{A_vB_{u,v}+A_uB_{v,w}}{B_{u,v}}\\A_u\ge\frac{A_wB_{u,v}+A_vB_{u,v}}{B_{v,w}}\end{cases}
{ A w ≥ B u , v A v B u , v + A u B v , w A u ≥ B v , w A w B u , v + A v B u , v
我們把上面的那個不等式代入下面去得到:
A u ≥ A v B u , v + A u B v , w B u , v × B u , v + A v B u , v B v , w = A v B u , v + A u B v , w + A v B u , v B v , w = A u + 2 A v B u , v B v , w
\begin{aligned}A_u &\ge \frac{\frac{A_vB_{u,v}+A_uB_{v,w}}{B_{u,v}}\times B_{u,v}+A_vB_{u,v}}{B_{v,w}}\\ &=\frac{A_vB_{u,v}+A_uB_{v,w}+A_vB_{u,v}}{B_{v,w}}\\ &=A_u+\frac{2A_vB_{u,v}}{B_{v,w}}\end{aligned}
A u ≥ B v , w B u , v A v B u , v + A u B v , w × B u , v + A v B u , v = B v , w A v B u , v + A u B v , w + A v B u , v = A u + B v , w 2 A v B u , v
移項得到:
2 A v B u , v B v , w ≤ 0
\frac{2A_vB_{u,v}}{B_{v,w}}\le 0
B v , w 2 A v B u , v ≤ 0
由於題目中給定的點權和邊權都是正數,所以這個不等式不成立,所以選擇一條鏈不能得到最大值。
故當點權和除以邊權和最大時,子圖中只有一條邊和它的兩個端點
參考代碼
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn = 500 ;
int N, M;
int A[ Maxn + 5 ] ;
int main ( ) {
#ifdef LOACL
freopen ( "in.txt" , "r" , stdin ) ;
freopen ( "out.txt" , "w" , stdout ) ;
#endif
double ans = 0 ;
scanf ( "%d %d" , & N, & M) ;
for ( int i = 1 ; i <= N; i++ )
scanf ( "%d" , & A[ i] ) ;
for ( int i = 1 ; i <= M; i++ ) {
int u, v, w;
scanf ( "%d %d %d" , & u, & v, & w) ;
ans = max ( ans, 1.0 * ( A[ u] + A[ v] ) / w) ;
}
printf ( "%.9f\n" , ans) ;
return 0 ;
}