网络流
Dinic 解最大流
还真是,这个算法不用太懂…直接add然后run就行,难点在建图,奥还有读题…
板子放最后
多源多汇 , 因为猪在猪圈里可以随意更改,所以对每一个猪圈,有一个人拿了出来之后,能转交给其他所有有这个钥匙的人任意数量的猪,最后所有人连上汇点,权重为这个人的需求即可
HDU 3416 Marriage Match IV (Dijkstra+最大流)
问题是求 从S到T的不经过同一条边的最短路数量,可以分成下面几个小问题
- 如何判断边是否在最短路径上?
最短路径满足条件是对现在的所有 [u->v] 边 都有: d[u] + cost <= d[v]
明显当 d[u] + cost == d[v] 时, [u->v] 的这条边在最短路径上- 如何计数?
冷静分析一波 , 假设现在就只有两个点 要计算 a->b 的 不经过同一个边最短路数量,那就是要计算 a->b 的边中有多少个和最小边相同的边数.可以发现,最短路上的权值不影响最后的计数了. 那么推展到n个结点 ,答案就是以最短路径建权值都是1的图,从 S->T的 最大流.
- 扩展 :当题目要求为不经过相同结点时怎么计数?
问题转化为结点容量为1 ,从S->T的最大流 ,拆点, 将路径上的每个点拆成 i 和 i+n 加权为1的边即可.
Dinic 解二分图匹配
因为每个人只能满意一次,要把人拆点,从源点到人的边权为食物,从人到汇点的边权为饮料
//vector存边,queue操作较慢
const ll inf = 0x3f3f3f3f;
const ll maxn = 1e5 + 7;
struct Dinic
{
struct edge
{
int to, cap, rev;
edge(int a, int b, int c)
{
to = a, cap = b, rev = c;
}
};
vector<edge> G[maxn];
int level[maxn];
int iter[maxn];
void init(int n)
{
memset(level, 0, sizeof level);
memset(iter, 0, sizeof iter);
for (int i = 0; i <= n; i++)
G[i].clear();
}
void add(int from, int to, int cap)
{
G[from].push_back(edge(to, cap, G[to].size()));
G[to].push_back(edge(from, 0, G[from].size() - 1));
}
void bfs(