题意:一个全白的网格,你要将一些格子涂黑,每次只能选一行或一列中的连续白格涂黑,问最小操作次数
先假装我们一次涂一个联通块,那么答案就是联通块个数,然后在这个基础上增加一些代价让方案变得合法
考虑这样建图:对两个水平相邻的要涂黑的格子$x,y$,建新点$u$,连$(S,u,1),(u,x,\infty),(u,y,\infty)$,对两个竖直相邻的要涂黑的格子$x,y$,建新点$v$,连$(x,v,\infty),(y,v,\infty),(v,T,1)$
如果存在一条$S\rightarrow u\rightarrow x\rightarrow v\rightarrow T$的路径,说明当前的涂色方案并不合法(染色转弯),于是我们需要把这条路径割掉,代表从联通块中分出一部分让答案变得合法,所以答案还要加上这个图的最小割
#include#include #include #include #include using namespace std;const int inf=2147483647;int h[7510],nex[40010],to[40010],cap[40010],M=1,S,T;void ins(int a,int b,int c){ M++; to[M]=b; cap[M]=c; nex[M]=h[a]; h[a]=M;}void add(int a,int b,int c){ ins(a,b,c); ins(b,a,0);}int dis[7510],q[7510];bool bfs(){ int head,tail,x,i; memset(dis,-1,sizeof(dis)); head=tail=1; q[1]=S; dis[S]=0; while(head<=tail){ x=q[head++]; for(i=h[x];i;i=nex[i]){ if(cap[i]&&dis[to[i]]==-1){ dis[to[i]]=dis[x]+1; if(to[i]==T)return 1; q[++tail]=to[i]; } } } return 0;}int cur[7510];int dfs(int x,int flow){ if(x==T)return flow; int us=0,i,t; for(i=cur[x];i&&flow;i=nex[i]){ if(cap[i]&&dis[to[i]]==dis[x]+1){ t=dfs(to[i],min(flow,cap[i])); cap[i]-=t; cap[i^1]+=t; us+=t; flow-=t; if(cap[i])cur[x]=i; } } if(us==0)dis[x]=-1; return us;}int dicnic(){ int ans=0; while(bfs()){ memcpy(cur,h,sizeof(h)); ans+=dfs(S,inf); } return ans;}int id[60][60];class BoardPainting{ public: int minimalSteps(vector mp){ int n,m,i,j,N,ans; n=mp.size(); m=mp[0].length(); N=2; S=1; T=2; ans=0; for(i=0;i v; char s[110]; for(scanf("%s",s);s[0]!='E';scanf("%s",s))v.push_back(s); printf("%d",cl.minimalSteps(v));}*/