poj Friendship 最小割 拆點

2021-08-07 05:49:50 字數 1859 閱讀 4247

題意:在乙個關係網中,如果說a與b保持聯絡,那麼a應該知道b的**號碼。或者存在c,a知道c的**號碼,c知道b的**號碼。可以認為如果a知道b的**號碼,那麼b也知道a的**號碼。在乙個關係網中可能會出現一些意外事故,比如某人更換手機號碼了,導致他與其他人都失去了聯絡。問給定兩個人s和t,問,最少多少人出現意外事故,使得s和t失去聯絡。

思路如果源點和匯點是直接相連的,那麼是」no anwer!」,然後拆點建圖,對每個點u拆成入點和出點,(u』,u」,1)代表u』到u」有一條容量為1的邊。在原圖中,直接與u相連的點v,在新建的圖中應該變成兩條邊(u」,v』,inf),(v」,u』,inf)。原圖中源點的出點,在新圖中作為源點,原圖匯點的入點,作為新建圖的匯點。跑一次最大流可以獲得最小割,即應該刪除的點數。題目要求按字典序輸出應該刪除的人,那麼從小到大列舉i(除了s和t),將i刪去,重新建圖,跑最大流,看獲得的最小割是否小於之前獲得的,如果小於,說明刪除的i點的「拆邊」正是之前跑最大流時被割中的邊,不用復原,將獲得的最小割減一重複這個過程,知道最小割為0。否則,i不是被割中的邊,那麼將i復原到圖中。

拆點類似這道題:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define cle(a) memset(a,0,sizeof(a))

#define inf(a) memset(a,0x3f,sizeof(a))

#define ll long long

#define rep(i,a,n) for(int i=a;i<=n;i++)

using

namespace

std;

const

int inf = ( 2e9 ) + 2;

const ll maxn = 500;

int mp[210][210];

struct dinic

};int s,t,n;

int d[maxn];

int cur[maxn];

vector

e; vector

g[maxn];

void addedge(int u,int v,int c)

void init()

bool bfs()}}

return d[t];

}int dfs(int u,int maxf,int t)

}return ret;

}int maxflow(int s,int t)

return flow;

}}dinic;

void build(int n)

}}int main()

build(n);

int mincut=dinic.maxflow(s+n,t);

int ans[210];

int cnt=0;

int buf[210],buf2[210];

for(int i=1;i<=n;i++) // 去掉i點

build(n);

int temp=dinic.maxflow(s+n,t);

if(mincut>temp)

else

if(mincut==0)break;

}printf("%d\n",cnt);

for(int i=0;iif(i!=cnt-1)

printf("%d ",ans[i]);

else

printf("%d\n",ans[i]);

}}

字典序最小最小割

通常,構造最小割時,我們對殘量網路進行bfs,設能夠到達的集合為s,不夠到達的集合為t 遍歷時考慮反向邊 則從s指向t的邊被割掉。但是有時,需要求字典序最小的最小割。我們可以把所有的邊從小到大排序,並遍歷。如果當前邊可以刪除,那麼就刪除它,否則繼續。一條邊 u,v,w 能被刪除有2個條件 這條邊滿流...

最小堆及基於最小堆的最小優先佇列

最小堆具有的性質 最小堆的父親節點比子節點的值小 在最小堆的類中我們定義的函式主要有 維護最小堆 建立最小堆和利用最小堆進行排序 以下是最小堆的定義 ifndef my min heap h define my min heap h include includeusing namespace st...

最小運算元

剛才在剛果準備挑戰最小運算元的。可是操作失誤,調教了白 在自己電腦上用c 環境試了試。竟然花了3個小時,哎,挑戰也是失敗了。題目詳情 給了a b兩個單詞和乙個單詞集合dict,每個的長度都相同。我們希望通過若干次操作把單詞a變成單詞b,每次操作可以改變單詞中的乙個字母,同時,新產生的單詞必須是在給定...