Compare commits

...

2 Commits

Author SHA1 Message Date
d9a9164d21 update 2025-08-25 11:27:39 +08:00
d704fe09d4 update 2025-08-25 11:25:01 +08:00

View File

@ -1,211 +1,40 @@
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
const int INF = 1e9;
// 边的结构体
struct Edge {
int to; // 边的终点
int capacity; // 边的容量
int rev; // 反向边的索引
};
class MaxFlow {
private:
int n; // 顶点数
std::vector<std::vector<Edge>> adj; // 邻接表
std::vector<int> level; // BFS分层图中的层次
std::vector<int> iter; // 当前弧优化
// 通过BFS构建分层图
bool bfs(int s, int t) {
level.assign(n + 1, -1);
std::queue<int> q;
level[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (const auto& edge : adj[u]) {
if (edge.capacity > 0 && level[edge.to] < 0) {
level[edge.to] = level[u] + 1;
q.push(edge.to);
}
}
}
return level[t] != -1;
}
// 通过DFS在分层图上寻找增广路并更新流量
int dfs(int u, int t, int f) {
if (u == t) return f;
for (int& i = iter[u]; i < adj[u].size(); ++i) {
Edge& e = adj[u][i];
if (e.capacity > 0 && level[u] < level[e.to]) {
int d = dfs(e.to, t, std::min(f, e.capacity));
if (d > 0) {
e.capacity -= d;
adj[e.to][e.rev].capacity += d;
return d;
}
}
}
return 0;
}
// 用于在残余网络中进行搜索以确定S可达和T可达的节点
void find_reachable(int start_node, std::vector<bool>& visited, bool reverse_edges = false) {
visited.assign(n + 1, false);
std::queue<int> q;
q.push(start_node);
visited[start_node] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for(const auto& edge : adj[u]){
// 在正向残余图上搜索S可达性
// S可达的条件是从u到v还有剩余容量
if (!reverse_edges && edge.capacity > 0 && !visited[edge.to]) {
visited[edge.to] = true;
q.push(edge.to);
}
// 在反向残余图上搜索T可达性
// v能到T的反向图 等价于 T能到v的反向图
// 条件是从u到v存在反向边容量 > 0 (即正向边流过流量)
if (reverse_edges && adj[edge.to][edge.rev].capacity > 0 && !visited[edge.to]) {
visited[edge.to] = true;
q.push(edge.to);
}
}
}
}
using namespace std;
class Solution {
public:
MaxFlow(int num_vertices) : n(num_vertices), adj(n + 1), level(n + 1), iter(n + 1) {}
// 添加一条从u到v容量为cap的边
void add_edge(int u, int v, int cap) {
adj[u].push_back({v, cap, (int)adj[v].size()});
adj[v].push_back({u, 0, (int)adj[u].size() - 1}); // 添加反向边
}
// 计算从s到t的最大流
int dinic(int s, int t) {
int flow = 0;
while (bfs(s, t)) {
iter.assign(n + 1, 0);
int f;
while ((f = dfs(s, t, INF)) > 0) {
flow += f;
vector<int> findDiagonalOrder(const vector<vector<int>>& m) {
int x=0,y=0;
bool isup=true;
vector<int> res;
res.reserve(m.size());
#define isout (x<0||x>m.size()||y<0||y>m[0].size())
do{
res.push_back(m[x][y]);
if(isup){
if(x==0){
++y;
isup=false;
}else{
--x;
++y;
}
}else{
if(y==0){
++x;
isup=true;
}else{
++x;
--y;
}
}
}
return flow;
}
// 统计最小割的数量
void count_min_cuts(int s, int t) {
// 第一步运行Dinic算法计算最大流这会改变adj列表中的capacity形成残余网络
int max_flow = dinic(s, t);
std::cout << "The minimum number of edges to remove is: " << max_flow << std::endl;
// 保存原始图结构因为add_edge会添加反向边
std::vector<std::pair<int, int>> original_edges;
// 注意:这里需要根据实际建图的方式来获取原始边
// 在这个简单实现中,我们硬编码原始边
original_edges = {
{1, 2}, {1, 3}, {1, 4},
{2, 4}, {2, 5},
{3, 4},
{4, 6},
{5, 7},
{6, 5}, {6, 7}
};
// 第二步在残余网络中确定S可达和T可达的顶点
std::vector<bool> reachable_from_s;
find_reachable(s, reachable_from_s, false);
std::vector<bool> can_reach_t; // 这里的名字意思是“能到达T的节点”
find_reachable(t, can_reach_t, true); // 在反向图上从T开始搜索
std::cout << "The sets of edges forming a minimum cut are:" << std::endl;
// 对于这个问题,我们可以直接找出所有"关键边",然后组合它们
// 但对于更复杂的问题,需要更复杂的算法
// 本题可以简化为:找到构成最小割的两个集合
// 割法 1S-side = {S可达节点}, T-side = {S不可达节点}
std::cout << "Cut set 1 (based on S-reachability):" << std::endl;
int count1 = 0;
for (const auto& p : original_edges) {
int u = p.first;
int v = p.second;
if (reachable_from_s[u] && !reachable_from_s[v]) {
std::cout << " (" << u << ", " << v << ")" << std::endl;
count1++;
}
}
// 割法 2T-side = {T能到达的节点}, S-side = {T不能到达的节点}
std::cout << "Cut set 2 (based on T-reachability):" << std::endl;
int count2 = 0;
for (const auto& p : original_edges) {
int u = p.first;
int v = p.second;
// u在S侧(不能到达T)v在T侧(能到达T)
if (!can_reach_t[u] && can_reach_t[v]) {
std::cout << " (" << u << ", " << v << ")" << std::endl;
count2++;
}
}
// 注意:如果两个割集完全一样,说明只有一个最小割。
// 在本题中,这两个方法会找到两个不同的割集。
if (count1 == max_flow && count2 == max_flow) {
if (count1 == count2) { // 检查两个割集是否相同, 简化处理
// A more robust check would compare the sets of edges.
// For this specific problem, we know they are different.
std::cout << "Total distinct minimum cuts found: 2" << std::endl;
} else {
std::cout << "Total distinct minimum cuts found: 2 (sets are different sizes, but both min-cuts)" << std::endl;
}
} else {
std::cout << "Only one minimum cut found." << std::endl;
}
}while(!(x==m.size()&&y==m[0].size()));
return res;
}
};
int main() {
// 设置OI/ACM风格的快速IO
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int main(){
int num_vertices = 7;
int source = 1;
int sink = 7;
MaxFlow solver(num_vertices);
// 根据题目中的图构建网络
// 所有边的容量都为1
solver.add_edge(1, 2, 1);
solver.add_edge(1, 3, 1);
solver.add_edge(1, 4, 1);
solver.add_edge(2, 4, 1);
solver.add_edge(2, 5, 1);
solver.add_edge(3, 4, 1);
solver.add_edge(4, 6, 1);
solver.add_edge(5, 7, 1);
solver.add_edge(6, 5, 1);
solver.add_edge(6, 7, 1);
solver.count_min_cuts(source, sink);
return 0;
Solution s;
s.findDiagonalOrder({{1,2,3},{4,5,6},{7,8,9}});
}