我做過的網路流題(持續更新)

2021-06-25 08:48:48 字數 4054 閱讀 2883

三個月前學的網路流, 當時其實也是沒有太明白, 就是套著模板做了幾道模板題, 這裡就不再說啦。

這兩天有從新翻出了網路流來做, 大致是按照那個《網路流建模彙總》做的

poj1149

有m個豬圈和n個顧客, 每個顧客可以取走指定豬圈裡一定限制內的豬, 取完後可以把所有他可以取得豬圈裡的豬任意移動。 這道題可以先模擬出來這張圖, 就是原點流向每個豬圈的節點, 容量為豬圈中豬的數量, 然後每來乙個人就需要所有代表在這個時刻豬圈狀態的節點, 把他可以取得豬圈和人連一條容量為無限大的邊, 再把人連向匯點, 這應該是

一種最直觀的構圖方式, 當時它的節點數是nm個的, 顯然需要優化, 有三個規律:

1, **完全相同的節點可以合併成乙個

2, 去向完全相同的節點可以合併成乙個

3, 如果點b只有點a乙個**, 且這條流的容量為無限大, 那麼顯然a和b可以合併成乙個

再加上更加顯然的相同兩個節點之間邊的合併, 然後經過種種簡化, 就會成了這個樣子了!

當然, 這種方法是一種比較通用的方法,雖然我現在應該不能自己倒出來最終的圖, 但這個也就像倒物理公式一樣, 相信我熟練掌握之後一定可以做到的!但也像推每個物理公式一樣, 我們總會有更加直觀的直接得出結論的方式, 雖然正著推出來可能性比較小, 但是得出結論後反著推一下還是沒有問題的。這道題中, 我們會發現, 一旦有任意兩個豬圈可以被同乙個人開啟, 那麼這兩個豬圈在以後就沒有任何區別了。 我們看第i個人取走的豬的組成是什麼: 首先, 如果有乙個豬圈是在之前沒有開啟過的, 那麼這個人從這個豬圈牽走豬的數量只能是0到這個豬圈的容量, 這樣就可以從原點到第i個人連一條容量為這個豬圈的容量的邊了, 其次, 一旦有乙個豬圈被前面的人開啟過了, 就可以發現以前開啟這個豬圈的那個人可以開啟的所有豬圈都可以作為第i個人取走豬的**了, 所以說我們只需要把前面的那個人跟第i個人連一條邊就可以了, 容量為inf, 因為前面該有的限制已經限制過了. 所以說最後構造出來的圖應該是和上圖一樣的!點數是n

5月份做的時候的**:

#include #include #include #include #include #include #define inf 1 << 25

using namespace std;

int headd[2005], level[2005], pig[2005], c[2005][2005];

int n, m, e = -1;

bool makelevel(int s, int t)

}

} return 0;

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

return ret;

}int dinic(int s, int t)

int main()

scanf("%d", &num);

c[i][n + 1] = num;

}printf("%d\n", dinic(0, n + 1));

// system("pause");

return 0;

}

現在的**(其實都一樣。。):

#include #include #include #include #include #include #define inf 1<<30

using namespace std;

int n, m, a[1005], head[1005], ee = -1, level[105], headj[1005];

struct edgeeedge[10005];

void addedge(int s, int t , int f)

bool makelevel(int s, int t)

} }return 0;

}int dfs(int now, int t, int maxf)return ret;

}int dinic(int s, int t)

int main()

else

} if(lala)

int dd; scanf("%d", &dd);

addedge(i, 101, dd);

} printf("%d\n", dinic(0, 101));

//system("pause");

return 0;

}

poj 1637

題意明確, 就是計算乙個混合圖是否存在尤拉迴路。

第一次見到不禁覺得思想非常巧妙, 深深滴被大神們鄙視了一番。。有向邊直接處理就好啦,  無向先給他任意定出乙個方向, 按照構建出來的有向圖式的無向圖建出圖, 然後如果入度減出度大於0 就把它與匯點連一條邊, 如果小於0 就把它與原點連一條邊, 容量都是入度減出度的二分之一的絕對值。判斷一下是否有滿流的方案就可以了!因為在這個圖里, 沒流一條邊, 就代表著把這條邊反向 , 總之真的是很機智啊!

poj 1459

就是發電廠那道題, 應該是很多人的網路流入門題吧。。所有點分為發電廠, 中轉站和消費者三種, 建立原點和匯點, 然後就行了。之所以再把它拿出來做是為了驗證我的dinic是不是寫錯了。。沒錯啊。。為什麼2112就是死活挑不出來55555,  難道是這道題的資料太弱了

#include #include #include #include #include #include #define inf 1<<30

using namespace std;

int n, np, nc, m, ee, head[250], level[250];

struct edgeee[40005];

void addedge(int s, int t, int f)

bool ml(int s, int t)

} }return 0;

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

if(ret == maxf)return ret;

} return ret;

}int dinic(int s, int t)

int main()

for(int i = 1; i <= np; i ++)

for(int i = 1; i <= nc; i ++)

printf("%d\n", dinic(n, n + 1));

} // system("pause");

return 0;

}

poj 2112

這道題據說是2391的簡化版, 我就想先刷一下, 然後沒想到就卡住了555就是看不出來**錯了。

#include #include #include #include #include #include #define inf 100000

using namespace std;

int k, c, m, edge[250][250], ee, head[250], level[250];

struct edgeee[40005];

void addedge(int s, int t, int f)

bool ml(int s, int t)

} }return 0;

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

} return ret;

}int dinic(int s, int t)

int main()

for(int p = 1; p <= k + c; p ++)

for(int i = 1; i <= k + c; i ++)

for(int j = 1; j <= k + c; j ++)

if(edge[i][j] > edge[i][k] + edge[k][j])

edge[i][j] = edge[i][k] + edge[k][j];

int l = 1, r = 40000;

while(l < r){

// printf("%d %d\n", l, r);

int mid = (l + r) / 2;

ee = -1;

// cout<

poj 2391

網路流(持續更新)

最後一種最快,前兩種彼此彼此 紫書模板 include include include include include include include include include include include includeusing namespace std struct edge int...

網路流最小割相關(持續更新)

12.6 今天看了下網路流,本想寫一篇部落格,但是想了想,畫圖太費勁,證明也不算特別難,那就先咕著了。前置知識 網路最大流 最好是dinic演算法 最大流最小割定理。一 割邊最少的最小割 題目 hdu3987 hdu6214 雙倍經驗 方法一 一次dinic 我們首先考慮,如何在求最大流的同時兼顧最...

我的ubuntu(持續更新中)

sudo apt get update sudo apt get upgrade注意 第1個指令是更新列表,第2個命令是執行公升級.安裝命令 sudo apt get remove ibus 如果已經是fcitx了,就不用這兩條了 sudo apt get install fcitx sudo ap...