mirror of
https://gitcode.com/Zengtudor/alg2025.git
synced 2025-09-04 01:01:43 +00:00
Compare commits
2 Commits
783bc1aac5
...
d9a9164d21
Author | SHA1 | Date | |
---|---|---|---|
d9a9164d21 | |||
d704fe09d4 |
233
src/test.cpp
233
src/test.cpp
@ -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;
|
||||
|
||||
// 对于这个问题,我们可以直接找出所有"关键边",然后组合它们
|
||||
// 但对于更复杂的问题,需要更复杂的算法
|
||||
// 本题可以简化为:找到构成最小割的两个集合
|
||||
|
||||
// 割法 1:S-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++;
|
||||
}
|
||||
}
|
||||
|
||||
// 割法 2:T-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}});
|
||||
}
|
Loading…
Reference in New Issue
Block a user