UVA10480 Sabotage —— 最小割最大流

 

题目链接:https://vjudge.net/problem/UVA-10480

 

 

 

题解:

实际就是求最小割集。

1.什么是网络流图的“割”?答:一个边的集合,使得网络流图删除这些边之后,点被分成两部分S和T, 且源点位于S中, 汇点位于T中。注意:不能存在独立于S和T的点。

2.对于最小割集中的边,它在残余网络中容量为0。

3.从源点出发,沿着有残余容量的边走,能够访问到的点都属于S集合,否则属于T集合。

 

 

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <cmath>
  7 #include <queue>
  8 #include <stack>
  9 #include <map>
 10 #include <string>
 11 #include <set>
 12 using namespace std;
 13 typedef long long LL;
 14 const int INF = 2e9;
 15 const LL LNF = 9e18;
 16 const int mod = 1e9+7;
 17 const int MAXN = 1e2+10;
 18 
 19 int maze[MAXN][MAXN];
 20 int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
 21 int flow[MAXN][MAXN];
 22 
 23 int sap(int start, int end, int nodenum)
 24 {
 25     memset(cur, 0, sizeof(cur));
 26     memset(dis, 0, sizeof(dis));
 27     memset(gap, 0, sizeof(gap));
 28     memset(flow, 0, sizeof(flow));
 29     int u = pre[start] = start, maxflow = 0, aug = INF;
 30     gap[0] = nodenum;
 31 
 32     while(dis[start]<nodenum)
 33     {
 34         loop:
 35         for(int v = cur[u]; v<nodenum; v++)
 36         if(maze[u][v]-flow[u][v]>0 && dis[u] == dis[v]+1)
 37         {
 38             aug = min(aug, maze[u][v]-flow[u][v]);
 39             pre[v] = u;
 40             u = cur[u] = v;
 41             if(v==end)
 42             {
 43                 maxflow += aug;
 44                 for(u = pre[u]; v!=start; v = u, u = pre[u])
 45                 {
 46                     flow[u][v] += aug;
 47                     flow[v][u] -= aug;
 48                 }
 49                 aug = INF;
 50             }
 51             goto loop;
 52         }
 53 
 54         int mindis = nodenum-1;
 55         for(int v = 0; v<nodenum; v++)
 56             if(maze[u][v]-flow[u][v]>0 && mindis>dis[v])
 57             {
 58                 cur[u] = v;
 59                 mindis = dis[v];
 60             }
 61         if((--gap[dis[u]])==0) break;
 62         gap[dis[u]=mindis+1]++;
 63         u = pre[u];
 64     }
 65     return maxflow;
 66 }
 67 
 68 bool vis[MAXN];
 69 void dfs(int u, int n)
 70 {
 71     vis[u] = true;
 72     for(int v = 0; v<n; v++)
 73         if(maze[u][v]-flow[u][v] && !vis[v])
 74             dfs(v, n);
 75 }
 76 
 77 int edge[MAXN*MAXN][2];
 78 int main()
 79 {
 80     int n, m;
 81     while(scanf("%d%d", &n, &m)&&(n||m))
 82     {
 83         memset(maze, 0, sizeof(maze));
 84         for(int i = 1; i<=m; i++)
 85         {
 86             int u, v, w;
 87             scanf("%d%d%d", &u,&v,&w);
 88             edge[i][0] = --u; edge[i][1] = --v;
 89             maze[u][v] = w;
 90             maze[v][u] = w;
 91         }
 92 
 93         int start = 0, end = 1;
 94         sap(start, end, n);
 95 
 96         memset(vis, false, sizeof(vis));
 97         dfs(0, n);
 98         for(int i = 1; i<=m; i++)
 99         {
100             int u = edge[i][0];
101             int v = edge[i][1];
102             if( (vis[u] && !vis[v]) || (!vis[u] && vis[v]) )
103                 printf("%d %d\n", u+1, v+1);
104         }
105         printf("\n");
106     }
107 }
View Code

 

转载于:https://www.cnblogs.com/DOLFAMINGO/p/8116494.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值