UVa 10480 Sabotage ( 最小割最大流定理)

本文介绍了一种利用最大流算法解决将网络中特定两点完全隔离的问题,通过最小割的概念来确定切断哪些连接最经济。文章详细展示了如何使用Dinic算法进行计算,并通过DFS寻找最小割集。

The regime of a small but wealthy dictatorship has been abruptly overthrown by an unexpected rebellion.
Because of the enormous disturbances this is causing in world economy, an imperialist military
super power has decided to invade the country and reinstall the old regime.
For this operation to be successful, communication between the capital and the largest city must
be completely cut. This is a difficult task, since all cities in the country are connected by a computer
network using the Internet Protocol, which allows messages to take any path through the network.
Because of this, the network must be completely split in two parts, with the capital in one part and
the largest city in the other, and with no connections between the parts.
There are large differences in the costs of sabotaging different connections, since some are much
more easy to get to than others.
Write a program that, given a network specification and the costs of sabotaging each connection,
determines which connections to cut in order to separate the capital and the largest city to the lowest
possible cost.
Input
Input file contains several sets of input. The description of each set is given below.
The first line of each set has two integers, separated by a space: First one the number of cities, n in
the network, which is at most 50. The second one is the total number of connections, m, at most 500.
The following m lines specify the connections. Each line has three parts separated by spaces: The
first two are the cities tied together by that connection (numbers in the range 1 − n). Then follows the
cost of cutting the connection (an integer in the range 1 to 40000000). Each pair of cites can appear
at most once in this list.
Input is terminated by a case where values of n and m are zero. This case should not be processed.
For every input set the capital is city number 1, and the largest city is number 2.
Output
For each set of input you should produce several lines of output. The description of output for each set
of input is given below:
The output for each set should be the pairs of cities (i.e. numbers) between which the connection
should be cut (in any order), each pair on one line with the numbers separated by a space. If there is
more than one solution, any one of them will do.
Print a blank line after the output for each set of input.
Sample Input
5 8
1 4 30
1 3 70
5 3 20
4 3 5
4 5 15
5 2 10
3 2 25
2 4 50
5 8
1 4 30
1 3 70
5 3 20
4 3 5
4 5 15
5 2 10
3 2 25
2 4 50
0 0
Sample Output
4 1
3 4
3 5
3 2
4 1
3 4
3 5
3 2

题意:一个国家出了内乱,现在想要把首都和最大的城市的通讯完全断开,但是断开一条边有花费,现在问断开哪些边可以使花费最小。

分析:跑一遍最大流dinic后,根据最小割定理,整部图被分为S,T两部分,从源点出发dfs得到S集的点,剩下的为T集的点,然后输出左右两边各一个连着的点就是割边。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod=609929123;
const int N=100220;
int n,f,d,m;
int S,T,R;//源点,汇点
struct node
{
    int v,cap,next;//领接表
}es[4*N];
int frist[N];
int dis[N];
int current[N];//当前弧优化
int x[N],y[N];
int vis[N];
int addedge(int u,int v,int cap)
{
    node  e1={v,cap,frist[u]};
    es[R]=e1;
    frist[u]=R++;
}
int bfs()
{
  queue<int>q;
  q.push(S);
  memset(dis,-1,sizeof(dis));
  dis[S]=0;
  while(!q.empty())
  {
      int h=q.front();
      if(h==T) return 1;
      q.pop();
      for(int i=frist[h];i!=-1;i=es[i].next)
      {
          int temp=es[i].v;
          if(dis[temp]==-1&&es[i].cap)
          {
              dis[temp]=dis[h]+1;
              q.push(temp);
          }
      }
  }
  return 0;
}
int dinic(int x,int maxflow)
{
  if(x==T) return maxflow;
  int flow,f=0;
  for(int &i=current[x];i!=-1;i=es[i].next)
  {
      int temp=es[i].v;
      if(dis[temp]==dis[x]+1&&es[i].cap)
      {
      flow=dinic(temp,min(maxflow-f,es[i].cap));
      es[i].cap-=flow;
      es[i^1].cap+=flow;
      f+=flow;
      if(f==maxflow) break;
      }
  }
  return f;
}
int DINIC()
{
 int ans=0;
 while(bfs())
 {
     int flow;
     memcpy(current,&frist,sizeof(frist));
     while(flow=dinic(S,inf))
     ans+=flow;
 }
 return ans;
}
void dfs(int x)//最小割 找出s部分的点
{
    vis[x]=1;
    for(int i=frist[x];i!=-1;i=es[i].next)
    {
        int temp=es[i].v;
        if(!vis[temp]&&es[i].cap)
             dfs(temp);
    }
}
int main()
{
    int u,v,cap;
   while(~scanf("%d%d",&n,&m)&&(n+m))
   {
       memset(frist,-1,sizeof(frist));
       R=0,S=1,T=2;
       for(int i=1;i<=m;i++)
       {
           scanf("%d%d%d",&x[i],&y[i],&cap);
           addedge(x[i],y[i],cap);
           addedge(y[i],x[i],cap);
       }
      DINIC();
      memset(vis,0,sizeof(vis));
      dfs(S);
      for(int i=1;i<=m;i++)
      {
          if((vis[x[i]]&&!vis[y[i]])||(vis[y[i]]&&!vis[x[i]]))
            printf("%d %d\n",x[i],y[i]);
      }
      printf("\n");
   }
}




### 数据包在网络协议栈中的流动路径 数据包在网络协议栈中的流动路径是一个复杂的过程,涉及多个层次的处理和转发逻辑。理解这一过程对于网络开发、调试以及性能优化至关重要。 #### 网络接口层的数据包接收 当数据包到达物理网卡时,首先由硬件驱动程序捕获,并封装成 `sk_buff` 结构体。这个结构体包含了数据包的所有相关信息,如源地址、目的地址、协议类型等。在桥接环境中,如果设备被配置为桥接模式,则数据包会直接进入桥接子系统进行处理[^2]。 ```c struct sk_buff *skb = netdev_alloc_skb(dev, size); ``` #### 桥接层的处理 在桥接模式下,数据包会被传递给桥接子系统。桥接层负责决定数据包是应该被本地处理(如 ARP 请求)还是被转发到其他端口。桥接 hook 的主要作用是在数据包进入 IP 层之前对其进行拦截和处理。例如,在 `NF_BR_PRE_ROUTING` hook 点,可以对数据包进行 MAC 地址过滤或 VLAN 标签剥离。 ```c static unsigned int bridge_hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { // 在此处添加自定义处理逻辑 return NF_ACCEPT; } ``` #### 传输层与网络层的处理 如果数据包的目的地址是本机,则会继续向上层协议栈传递。IP 层负责解析 IP 头部,并根据协议字段将数据包传递给相应的传输层协议(如 TCP 或 UDP)。在这个过程中,Netfilter 的 IPv4 hook 可以用于实现基于 IP 地址、端口、协议等字段的过滤规则,以及 SNAT/DNAT 转换。 ```c static unsigned int ipv4_hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { // 在此处添加自定义处理逻辑 return NF_ACCEPT; } ``` #### 应用层的数据包处理 最终,经过 IP 层和传输层处理后的数据包会被传递给应用程序。应用程序可以通过 socket 接口读取这些数据包,并进行进一步的处理。在整个过程中,Netfilter 提供了多种 hook 点,允许开发者在网络协议栈的不同阶段对数据包进行拦截和修改。 #### 网桥-NF 模式下的三层处理 若启用了桥接-NF(bridge-nf)功能,则网桥可以将数据包传递给 IP 层进行处理。此时,可以使用 `NFPROTO_IPV4` 类型的 hook 来实现对桥接流量的 IP 层过滤或 NAT。在这种模式下,网桥会调用 `ip_sabotage_in` 函数来防止数据包重复进入 IP 层的 `NF_INET_PRE_ROUTING` 钩子。 #### 多接口系统的处理 在多接口系统中,数据包可能会从一个接口进入并被转发到另一个接口。这种情况下,Netfilter 的 hook 机制同样适用。例如,在 `NF_INET_FORWARD` hook 点,可以对转发的数据包进行过滤或修改。 ```c static struct nf_hook_ops ipv4_nfops __read_mostly = { .hook = ipv4_hook_func, .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_FIRST + 10, }; ``` #### 测试与调试 在内核模块开发过程中,应充分利用 `nf_log`、`kprobe` 等工具对 hook 回调函数的行为进行日志记录和调试,以确保其按预期工作。此外,还可以通过 `sysctl` 参数调整桥接-NF 的行为,如 `net.bridge.bridge-nf-call-iptables`。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值