hdu 3046 最大流
题意:n×m的棋盘,上面有羊和狼,可以在格子四条边上修护栏,问最少修多少护栏可以使狼吃不到羊?
分析:超级源点连狼,超级汇点连羊,容量无穷大,求最小割。
#define M 40010 struct Node{ int c,v,next; }E[999999]; int head[M]; int gap[M],dis[M],pre[M],cur[M],d[M]; int NE,NV; int sap(int s,int t) { memset(dis,0,sizeof(int)*(NV+1)); memset(gap,0,sizeof(int)*(NV+1)); FOR(i,0,NV) cur[i] = head[i]; int u = pre[s] = s, maxflow = 0; gap[0] = NV; d[s]=0x7fffffff; while(dis[s] < NV) { while(1){ for(int &i = cur[u]; i != -1; i = E[i].next) { int v = E[i].v; //cout<<u<<' '<<v<<' '<<i<<' '<<E[i].next<<endl; if(E[i].c && dis[u] == dis[v] + 1) { d[v] = min(d[u], E[i].c); pre[v] = u; u = v; if(v == t) { int temp = s, flow = d[t]; maxflow += d[t]; for(u = pre[u];v != s;v = u,u = pre[u]) { E[cur[u]].c -= flow; E[cur[u]^1].c += flow; d[v] -= flow; if(d[v] && temp == s) temp = v;//瓶颈边的前一条边 } u = temp; } break; } } if(cur[u] == -1) break; } if(!(--gap[ dis[u] ])) break; dis[u] = NV-1; for(int i = head[u]; i != -1 ; i = E[i].next) { int v = E[i].v; if(E[i].c && dis[u]>dis[v]+1) { cur[u] = i; dis[u] = dis[v]+1; } } gap[dis[u]] ++; u = pre[u]; } return maxflow; } int sap1(int s,int t) { memset(dis,0,sizeof(int)*(NV+1)); memset(gap,0,sizeof(int)*(NV+1)); FOR(i,0,NV) cur[i] = head[i]; int u = pre[s] = s,maxflow = 0,aug = -1; gap[0] = NV; while(dis[s] < NV) { loop: for(int &i = cur[u]; i != -1; i = E[i].next) { int v = E[i].v; if(E[i].c && dis[u] == dis[v] + 1) { checkmin(aug,E[i].c); pre[v] = u; u = v; if(v == t) { maxflow += aug; for(u = pre[u];v != s;v = u,u = pre[u]) { E[cur[u]].c -= aug; E[cur[u]^1].c += aug; } aug = -1; } goto loop; } } int mindis = NV; for(int i = head[u]; i != -1 ; i = E[i].next) { int v = E[i].v; if(E[i].c && mindis > dis[v]) { cur[u] = i; mindis = dis[v]; } } if( (--gap[dis[u]]) == 0) break; gap[ dis[u] = mindis+1 ] ++; u = pre[u]; } return maxflow; } void Insert(int u,int v,int c,int cc ) {//形成了一些重边 E[NE].c = c; E[NE].v = v; E[NE].next = head[u]; head[u] = NE++; E[NE].c = cc; E[NE].v = u; E[NE].next = head[v]; head[v] = NE++; } void shuchu(){ cout<<E[61].next<<' '<<E[80].next<<' '<<E[78].next<<' '<<E[77].next<<endl; } int n,m; void build(){ int t=n*m+1; FOE(i,1,n) FOE(j,1,m){//每个格子向右边和下边建图 int u = (i-1)*m+j; int v1= u+1, v2=u+m, v; if(j<m) Insert(u, v1, 1, 1); if(i<n) Insert(u, v2, 1, 1); scanf("%d",&v); if(v==1) Insert(0, u, 11111111, 11111111); else if(v==2) Insert(u, t, 11111111, 11111111); } //shuchu(); } int main() { // READ // WRITE int p=0; while(~scanf("%d%d",&n,&m)){ p++; NV = n*m+2; FOR(i,0,NV) head[i] = -1; NE = 0; build(); //FOR(i,0,NV)cout<<head[i];cout<<endl; printf("Case %d:\n%d\n",p,sap1( 0, NV-1)); //cout<<E[61].next<<endl; } }