最小割,边max为60w条!
虚拟源点连狼,容量为INF,羊连虚拟汇点,容量为INF。
狼和空格向旁边的空格和羊连容量为1的边
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 100 + 10; const int maxm = 60000 + 10; const int maxv = 10000 + 10; const int INF = 0x3f3f3f3f; int n,m,e,vid,S,T; int h[maxv],v[maxm],next[maxm],f[maxm]; int dist[maxv],gap[maxv]; int a[maxn][maxn],id[maxn][maxn]; int dx[] = {1,0,-1,0}; int dy[] = {0,1,0,-1}; void add(int a,int b,int F) { v[e] = b; next[e] = h[a]; f[e] = F; h[a] = e++; v[e] = a; next[e] = h[b]; f[e] = 0; h[b] = e++; } void build() { scanf("%d%d",&n,&m); memset(h,-1,sizeof(h)); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { scanf("%d",&a[i][j]); id[i][j] = ++vid; } S = ++vid; T = ++vid; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { if(a[i][j] == 1) add(S,id[i][j],INF); else if(a[i][j] == 2) add(id[i][j],T,INF); for(int d = 0,x,y; d < 4; d++) if(id[x=i+dx[d]][y=j+dy[d]]) if(a[i][j] != 2 && a[x][y] != 1) add(id[i][j],id[x][y],1); } } int ISAP(int u,int flow) { if(u == T) return flow; int cur = 0,aug,mindist = vid; for(int i =h[u];~i;i=next[i]) if(f[i] && dist[u] == dist[v[i]] + 1) { aug = ISAP(v[i],min(f[i],flow-cur)); f[i] -= aug; f[i^1] += aug; cur += aug; if(cur == flow || dist[S] >= vid) { return cur; } } if(cur == 0) { if(!--gap[dist[u]]) { dist[S] = vid; return cur; } for(int i = h[u];~i;i=next[i]) if(f[i]) mindist = min(mindist,dist[v[i]]); ++gap[dist[u]=mindist+1]; } return cur; } int min_cut1() { gap[0] = vid; int res = 0; while(dist[S] < vid) { res += ISAP(S,INF); } return res; } void solve() { printf("%d ",min_cut1()); } int main() { build(); solve(); return 0; }