您的位置:首页 > 其它

BZOJ1001: [BeiJing2006]狼抓兔子 (最小割)

2015-11-15 13:06 288 查看
传送门

题目大意:求给出图的最小割(……题目就是这个意思)。

明眼一看,这就是一个裸的最大流,可是被数据范围吓住了,有106个点,然后又有3∗106条边,对于网络流可怜的O(n2m)的时间复杂度来说,简直是怪兽……但之前有同学告诉我,这道题就是最大流,我就硬着头皮上了一个ISAP,光荣超时,然后去找题解(想不出来了……)发现了两种,一种是把每一个面当做一个点,然后做最短路,即得最小割的容量,另一种竟然还是硬上网络流……黄学长用的dinic只用了800ms,而我之前的ISAP却用了15000+ms这不科学啊。然后我尝试着预标号,然后再ISAP,竟然只要500ms,太神了……

以后一定记住,要先预处理一遍!

代码:

/**************************************************************
Problem: 1001
User: geng4512
Language: C++
Result: Accepted
Time:552 ms
Memory:87896 kb
****************************************************************/

#include<cstdio>
#include<cstring>
const int MAXN = 1001*1001;
inline int min(int a, int b) {return a < b ? a : b;}
int ecnt = -1;
struct node {
int v, w, nxt;
}Edge[MAXN*6];
int Adj[MAXN], q[MAXN];
bool vis[MAXN];
void Addedge(int u, int v, int w) {
node *t = &Edge[++ ecnt];
t->v = v; t->w = w; t->nxt = Adj[u];
Adj[u] = ecnt;
t = &Edge[++ ecnt];
t->v = u; t->w = w; t->nxt = Adj[v];
Adj[v] = ecnt;
}
char c;
inline void GET(int &n) {
n = 0;
do c = getchar(); while(c > '9' || c < '0');
while('0' <= c && c <= '9') {n=n*10+c-'0';c=getchar();}
}
int n, m, ans, S, T, d[MAXN], vd[MAXN], N;
int aug(int u, int augco) {
int dmin = N-1, augc = augco, delta;
if(u == T) return augco;
for(int i = Adj[u]; ~i; i = Edge[i].nxt)
if(Edge[i].w > 0) {
if(d[Edge[i].v]+1 == d[u]) {
delta = min(augc, Edge[i].w);
delta = aug(Edge[i].v, delta);
Edge[i].w -= delta;
Edge[i^1].w += delta;
augc -= delta;
if(d[S] >= N) return augco - augc;
if(!augc) return augco;
}
if(dmin > d[Edge[i].v]) dmin = d[Edge[i].v];
}
if(augco == augc) {
-- vd[d[u]];
if(!vd[d[u]]) d[S] = N;
d[u] = ++ dmin;
++ vd[dmin];
}
return augco - augc;

}
void bfs() {
int l = 0, r = 0, u;
q[++ r] = T; vis[T] = 1; vd[0] ++;
while(l < r) {
u = q[++ l];
for(int i = Adj[u]; ~i; i = Edge[i].nxt) {
if(vis[Edge[i].v]) continue;
d[Edge[i].v] = d[u] + 1;
++ vd[d[u]+1];
vis[Edge[i].v] = 1;
q[++r] = Edge[i].v;
}
}
}
void sap() {
bfs();
while(d[S] < N)
ans += aug(S, 0x7fffffff);
}
int main()
{
int w;
memset(Adj, -1, sizeof Adj);
GET(n); GET(m);
for(int i = 0; i < n; ++ i)
for(int j = 0; j < m-1; ++ j) {
GET(w);
Addedge(i*m+j, i*m+j+1, w);
}
for(int i = 0; i < n-1; ++ i)
for(int j = 0; j < m; ++ j) {
GET(w);
Addedge(i*m+j, (i+1)*m+j, w);
}
for(int i = 0; i < n-1; ++ i)
for(int j = 0; j < m-1; ++ j) {
GET(w);
Addedge(i*m+j, (i+1)*m+j+1, w);
}
T = n*m-1; N = n*m;
sap();
printf("%d\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: