P1345 [USACO5.4]奶牛的电信Telecowmunication【最小割】【最大流】
题目描述
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相连,a2与a3相连,等等,那么电脑a1和a(c)就可以互发电邮。
很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。
有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值。
以如下网络为例:
1* / 3 - 2*
这张图画的是有2条连接的3台电脑。我们想要在电脑1和2之间传送信息。电脑1与3、2与3直接连通。如果电脑3坏了,电脑1与2便不能互发信息了。
输入格式
第一行 四个由空格分隔的整数:N,M,c1,c2.N是电脑总数(1<=N<=100),电脑由1到N编号。M是电脑之间连接的总数(1<=M<=600)。最后的两个整数c1和c2是上述两头奶牛使用的电脑编号。连接没有重复且均为双向的(即如果c1与c2相连,那么c2与c1也相连)。两台电脑之间至多有一条连接。电脑c1和c2不会直接相连。
第2到M+1行 接下来的M行中,每行包含两台直接相连的电脑的编号。
输出格式
一个整数表示使电脑c1和c2不能互相通信需要坏掉的电脑数目的最小值。
输入输出样例
输入 #1
3 2 1 2 1 3 2 3
输出 #1
1
思路
肯定是最小割,直接交不要怂
观察一下,这是蓝题,不会有这样的送分题的。
再观察一下,发现踩烂的是电脑。
所以就变成了求最小割点。不是tarjan
最小割点的求法: 把每个点拆成流入流出两个点, 中间连一条费用为 1 的边,这条边被破坏即这个点被破坏。
点与点之间理所应当连inf的容量,保证不会把连线给拆了。
CODE
1 #include <bits/stdc++.h> 2 #define dbg(x) cout << #x << "=" << x << endl 3 #define eps 1e-8 4 #define pi acos(-1.0) 5 6 using namespace std; 7 typedef long long LL; 8 9 template<class T>inline void read(T &res) 10 { 11 char c;T flag=1; 12 while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; 13 while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; 14 } 15 16 namespace _buff { 17 const size_t BUFF = 1 << 19; 18 char ibuf[BUFF], *ib = ibuf, *ie = ibuf; 19 char getc() { 20 if (ib == ie) { 21 ib = ibuf; 22 ie = ibuf + fread(ibuf, 1, BUFF, stdin); 23 } 24 return ib == ie ? -1 : *ib++; 25 } 26 } 27 28 int qread() { 29 using namespace _buff; 30 int ret = 0; 31 bool pos = true; 32 char c = getc(); 33 for (; (c < '0' || c > '9') && c != '-'; c = getc()) { 34 assert(~c); 35 } 36 if (c == '-') { 37 pos = false; 38 c = getc(); 39 } 40 for (; c >= '0' && c <= '9'; c = getc()) { 41 ret = (ret << 3) + (ret << 1) + (c ^ 48); 42 } 43 return pos ? ret : -ret; 44 } 45 46 const int maxn = 1e4 + 7; 47 const int inf = 0x3f3f3f3f; 48 49 int n,m,cnt = 1,s,t; 50 51 int maxflow; 52 int head[maxn]; 53 54 struct Node { 55 int v,dis,nxt; 56 }edge[maxn << 2]; 57 58 void BuildGraph(int u,int v,int dis){ 59 edge[++cnt].nxt = head[u]; 60 edge[cnt].v = v; 61 edge[cnt].dis = dis; 62 head[u] = cnt; 63 64 edge[++cnt].nxt = head[v]; 65 edge[cnt].v = u; 66 edge[cnt].dis = 0; 67 head[v] = cnt; 68 } 69 70 int depth[maxn]; 71 72 bool bfs() { 73 queue<int> q; 74 while(!q.empty()) 75 q.pop(); 76 memset(depth,0,sizeof(depth)); 77 depth[s] = 1; 78 q.push(s); 79 while(!q.empty()){ 80 int u = q.front(); 81 q.pop(); 82 for(int i = head[u]; i; i = edge[i].nxt){ 83 int v = edge[i].v; 84 if(edge[i].dis && !depth[v]){ 85 depth[v] = depth[u] + 1; 86 if(v == t) 87 return true; 88 q.push(v); 89 } 90 } 91 } 92 return false; 93 } 94 95 int Dinic(int u,int flow) {//最大流 96 if(u == t) 97 return flow; 98 int rest = flow,temp;//残量网络 99 for(int i = head[u];i;i = edge[i].nxt) { 100 int v = edge[i].v; 101 if(depth[v] == depth[u] + 1 && edge[i].dis){ 102 temp = Dinic(v,min(rest,edge[i].dis)); 103 if(!temp)depth[v] = 0; 104 rest -= temp; 105 edge[i].dis -= temp; 106 edge[i ^ 1].dis += temp; 107 } 108 } 109 return flow - rest; 110 } 111 112 int main(){ 113 scanf("%d %d %d %d",&n, &m, &s, &t); 114 for(int i = 1;i <= n;i++){ 115 BuildGraph(i, i + n, 1); 116 } 117 118 int u,v; 119 for(int i = 1; i <= m; i++){ 120 scanf("%d %d",&u, &v); 121 BuildGraph(u + n,v,inf); 122 BuildGraph(v + n,u,inf); 123 } 124 s += n; 125 int flow = 0; 126 while(bfs()){ 127 while(flow = Dinic(s,inf)) 128 maxflow += flow; 129 } 130 printf("%d\n",maxflow); 131 return 0; 132 }