POJ 1815 Friendship

这道题纠结了一天,终于还是写出来了。

这道题就是一个求源和汇联通度的题,转换过来就是最大流最小割问题。之前也做过一些最大流的题,但都只是单纯的最大流而已,算不上难题。这题是我的第一道最小割~~

刚开始有好几个地方想错了:
1.求最小割。刚开始是在网络里面找满流边,后来才发现是错的,需要从源点开始进行DFS,具体分析网上有一篇很好的论文。
2.枚举。这道题要求有多个最小割的情况是,按字典顺序输出割点。开始不知道怎么枚举,还用到了DFS,在一条流里面找最小割点,然后把找到的割点排序输出。WA了很久,最后还是放弃。在网上看到一个枚举点,删除点求流量是否减少,如果减少则该点为割点。当然,枚举时按照点的编号从小到大枚举就可以了。

总的来说,做了这题,有两个收获:
1.会求最小割了。
2.学会了一种新的思路。

Just do it. 继续加油。第一篇博文,希望大家支持,谢谢。

ContractedBlock.gif ExpandedBlockStart.gif Code
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4  
  5 using namespace std;
  6  
  7 #define M(x, n) memset(x, n, sizeof(x))
  8  
  9 struct Edge {
 10         int u, v, w;
 11         struct Edge *next, *neg;
 12         Edge() {}
 13         Edge(const int &U, const int &V, const int &W)
 14                 :u(U), v(V), w(W){}
 15 }mem[1<<19];
 16  
 17 const int MaxN = 210, inf = 0x7fffffff;
 18  
 19 struct Map {
 20         int map[MaxN][MaxN], n;
 21         Map modify(int x) {
 22                 Map tmp;
 23                 tmp.n = n;
 24                 for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) {
 25                         if(i == x || j == x)
 26                                 tmp.map[i][j] = 0;
 27                         else
 28                                 tmp.map[i][j] = map[i][j];
 29                 }
 30                 return tmp;
 31         }
 32         void del(int x) {
 33                 for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) {
 34                         if(i == x || j == x)
 35                                 map[i][j] = 0;
 36                 }
 37         }
 38 }MM;
 39  
 40 Edge *adj[MaxN<<1], *pre[MaxN<<1];
 41 int n, src, dst, mtp;
 42 int q[MaxN<<1], qs, qe;
 43 int f[MaxN<<1], mark[MaxN<<1], cut[MaxN<<1];
 44  
 45 inline void addedge(const int &u, const int &v, const int &w) {
 46         mem[mtp] = Edge(u, v, w);
 47         mem[mtp].next = adj[u]; adj[u] = mem + mtp++;
 48         mem[mtp] = Edge(v, u, 0);
 49         mem[mtp].next = adj[v]; adj[v] = mem + mtp++;
 50         adj[u]->neg = adj[v]; adj[v]->neg = adj[u];
 51 }
 52  
 53 void build_graph(const Map &M) {
 54         mtp = 0;
 55         for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) {
 56                 if(M.map[i][j] && i != j) {
 57                         addedge(i+n, j, inf);
 58                 }
 59                 else if(i == j) {
 60                         if(i == src)
 61                                 addedge(i, i+n, inf);
 62                         else
 63                                 addedge(i, i+n, 1);
 64                 }
 65         }
 66 }
 67  
 68 bool spfa() {
 69         int u, v;
 70         Edge *p;
 71         M(mark, 0); M(f, 0); M(pre, 0);
 72         f[src] = inf; mark[src] = true; pre[src] = NULL;
 73         q[0= src; qs = 0; qe = 1;
 74         while(qs != qe) {
 75                 u = q[qs++]; if(qs == MaxN) qs = 0;
 76                 for(p = adj[u]; p; p = p->next) {
 77                         v = p->v;
 78                         if(!mark[v] && p->> 0) {
 79                                 f[v] = p->> f[u] ? f[u] : p->w;
 80                                 pre[v] = p;
 81                                 mark[v] = true;
 82                                 q[qe++= v; if(qe == MaxN) qe = 0;
 83                         }
 84                 }
 85                 if(f[dst] > 0)
 86                         return true;
 87         }
 88         if(f[dst] > 0)
 89                 return true;
 90         return false;
 91 }
 92  
 93 int MaxFlow(const Map &MM) {
 94         M(adj, 0);
 95         build_graph(MM);
 96         int flow = 0;
 97         while(spfa()) {
 98                 Edge *p;
 99                 int u;
100                 flow += f[dst];
101                 for(p = pre[dst]; p; p = pre[u]) {
102                         p->-= f[dst];
103                         p->neg->+= f[dst];
104                         u = p->u;
105                 }
106         }
107         return flow;
108 }
109  
110 int main() {
111         while(scanf("%d%d%d"&n, &src, &dst) == 3) {
112                 MM.n = n;
113                 for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) {
114                         scanf("%d"&MM.map[i][j]);
115                 }
116                 if(MM.map[src][dst]) {
117                         printf("NO ANSWER!\n");
118                         continue;
119                 }       
120                 int Flow = MaxFlow(MM);
121                 int ctp = 0;
122                 printf("%d\n", Flow);
123                 for(int i = 1; i <= n; ++i) {
124                         if(i == src || i == dst) continue;
125                         int t = MaxFlow(MM.modify(i));
126                         if(t < Flow) {
127                                 Flow--;
128                                 cut[ctp++= i;
129                                 MM.del(i);
130                         }
131                         if(!t)
132                                 break;
133                 }
134                 for(int i = 0; i < ctp; ++i) {
135                         if(i) {printf(" %d", cut[i]);continue;}
136                         printf("%d", cut[i]);
137                 }
138                 if(ctp)
139                         putchar(10);
140         }
141         return 0;
142 }
143 

转载于:https://www.cnblogs.com/destinydesigner/archive/2009/09/27/1574950.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值