P2172 [国家集训队]部落战争(最小路径覆盖)
每个点仅走一次:最小路径覆盖
套路地拆点,具体看代码中的$draw()$
流量每增加1,意味着一支军队可以多走一格,代价减少1
最后答案即为总点数$-dinic()$
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9') f=f&&(c!='-'),c=getchar(); while('0'<=c&&c<='9') x=x*10+c-48,c=getchar(); return f?x:-x; } #define M 400000 int n,m,R,C,S,T,d[M],cur[M],tt; char q[100][100]; bool vis[M]; int Cnt=1,hd[M],nxt[M],ed[M],poi[M],val[M]; void adde(int x,int y,int v){ nxt[ed[x]]=++Cnt; hd[x]=hd[x]?hd[x]:Cnt; ed[x]=Cnt; poi[Cnt]=y; val[Cnt]=v; } void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);} #define to poi[i] bool Bfs(){ memset(vis,0,sizeof(vis)); queue <int> h; h.push(S); vis[S]=1; d[S]=0; while(!h.empty()){ int x=h.front(); h.pop(); for(int i=hd[x];i;i=nxt[i]) if(!vis[to]&&val[i]>0) vis[to]=1,d[to]=d[x]+1,h.push(to); }return vis[T]; } int Dfs(int x,int a){ if(!a||x==T) return a; int F=0,f; for(int &i=cur[x];i;i=nxt[i]) if(d[to]==d[x]+1&&(f=Dfs(to,min(a,val[i])))>0){ F+=f,a-=f,val[i]-=f,val[i^1]+=f; if(!a) break; } return F; } int Dinic(){ int re=0; while(Bfs()){ for(int i=1;i<=T;++i) cur[i]=hd[i]; re+=Dfs(S,1e9); }return re; } bool is(int x,int y){return x>0&&x<=n&&y>0&&y<=m&&q[x][y]=='.';} int id(int x,int y){return x*m-m+y;} void draw(int x,int y){ int p=id(x,y); ++tt; link(S,p,1); link(p+n*m,T,1); if(is(x+R,y+C)) link(p,id(x+R,y+C)+n*m,1); if(is(x+R,y-C)) link(p,id(x+R,y-C)+n*m,1); if(is(x+C,y+R)) link(p,id(x+C,y+R)+n*m,1); if(is(x+C,y-R)) link(p,id(x+C,y-R)+n*m,1); } int main(){ scanf("%d%d%d%d",&n,&m,&R,&C); S=n*m*2+1; T=S+1; for(int i=1;i<=n;++i) scanf("%s",q[i]+1); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(q[i][j]=='.') draw(i,j); printf("%d\n",tt-Dinic()); return 0; }