在乙個合法的連通圖中,每條邊都有乙個邊權,我們欽定一條邊。然後對圖進行一些操作:將某一條邊的權值+1或-1。請問至少多少次後可以使欽定的邊出現在該圖的最小生成樹中。
luogu傳送門:[shoi2010]最小生成樹
解題思路:
說實話:我們一定要跳出題目的侷限性,畢竟網路流是屬於圖演算法。
我們考慮,為什麼我們欽定的邊會不在最小生成樹上,很簡單,有更多比它更小的邊。並且,能夠更新我們欽定邊的邊一定會和我們欽定的邊成環(我們考慮kruscal的實現過程,如果想不明白,可以看看 嚴格次小生成樹 )。
在這道題中更為簡單,由上述條件,我們只需要對於每一條比我們欽定邊target小的邊建立一條權值為
權值 = t[ target ].val - t[ i ].val + 1
的流邊即可。然後轉化為最小割模型即可。
模型轉化:
我很想把它提出來講。
我們既然要找到一條符合的邊,那麼就是要讓最小生成樹經過欽定邊target,經過的前提就是可以到達target邊上兩點的其他路徑都沒有target更優,那麼,然這些邊增大即可。這樣一想,感覺就是讓這兩點之間的其他路徑都比target邊的邊權大。
我們對這些原本更小的邊都計算於target邊權的差值,然後跑最小割。
口糊合法性:
1.這些邊都小於target的邊權,如果更大,那麼它本身就不可以能優於target邊,就不可能在target之前進入最小生成樹
2.由1可知,上述建出的流圖中無負邊權(流量為負),所以流演算法是可行的。(最小割 = 最大流 )
3.如果target就在原本的最小生成樹上,那麼流圖是不連通的,所以出題人是卡不了的。
注:樓主作死寫了hlpp,完全可以用dinic打,而且lll優化後還更快一些,當然隨機資料hlpp絕對有時間上的優勢。
ac code:
#includeusing namespace std;
const int maxn = 100010 , inf = ( 1 << 30 ) ;
inline int read()
while(g>='0'&&g<='9')
return s*w;
}int tot = 1 , to[ maxn ] , nex[ maxn ] , head[ 10005 ] , w[ maxn ] , n , m , t , s , target ;
int d[ 10005 ] , e[ 10005 ] , h[ 10005 ] , numh[ maxn ] ;
bool v[ maxn ] ;
struct apt[ maxn ];
void add( int x , int y , int z )
void relabel( int u )
}struct cmp}}
}return;
}void push_(int u)
if( !e[u] )break;}}
}int hlpp()}}
while(!q.empty())
}relabel( u ) ;
numh[ h[ u ] ]++ ;
q.push( u ) ;
v[ u ] = true ;}}
return e[ t ] ;
} void prepare()
int main()
}cout
}
SHOI2010 最小生成樹
嘟嘟嘟 這道題的切入點在於模型的轉化。令第 lab 條邊連線的兩個點分別為 x,y 根據kruskal演算法,我們排完序加邊的時候,在執行第 lab 條邊之前,都要保證 x,y 不連通。這就很像最小割了。所以我們把邊權小於 w 的都拿來建圖,那邊權是啥咧?題中說的除了一條邊其餘的都減1,那不就相當於...
SHOI2010 最小生成樹(貪心)(最小割)
首先這個全域性 1可以等價成單點 1。考慮建樹的kruskal演算法。發現其實就是要求在加入權值小於等於這條邊的那些邊的時候,s,t s,ts,t不連通。顯然最小割。include define ll long long define re register define cs const cs i...
最小生成樹 次小生成樹
一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...