1 条题解
-
0
自动搬运
来自洛谷,原作者为

George1123
**搬运于
2025-08-24 21:45:55,当前版本为作者最后更新于2020-01-04 12:08:42,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
此题算法:费用流
题目很简洁,做法很恶心的典型。
因为是网络流题,所以模板就不说了,只考虑加边。
大致思路:
简化问题
记录初始和结束状态,把白棋看作没棋。
把开始结束都有黑棋的格子看作没棋。
如果开始结束时黑棋数不等, 掉。
加边
1.拆点,每个格子有格子 和格子 。
控制格子交换次数。
2. 向每个黑棋格 连流量 费用 的边。
表示需匹配状态。
3.每个黑棋格 向 连流量 费用 的边。
表示匹配状态。
4.每个格子 向对应 连流量 允许交换数 费用 的边。
两次交换只会消耗 的流量。
※.如果格子初始或结束时有黑棋并且允许交换数为奇数,在上面那条边上附上 的流量。
不交换本来就要通过的流量。
5.每个格子 向八连通的格子 连流量 费用 的边。
用来交换。
然后跑模板就好了,网络流的题都差不多。

图片仅供参考,以实物为准。
以下是代码 注释
#include <bits/stdc++.h> using namespace std; const int N=1e3+10; const int M=5e4+10; const int inf=1e8+10; int p,n,m,s,t,S,T,fans,cans; struct edge{ int adj,nex,fw,r; }e[M]; int g[N],top=1; void add(int x,int y,int z,int w){ e[++top]=(edge){y,g[x],z,w}; g[x]=top; } void Add(int x,int y,int z,int w){ add(x,y,z,w),add(y,x,0,-w); } int dep[N],cur[N]; bool vis[N]; queue<int> Q; bool spfa(){ // puts("spfa()"); for(int i=1;i<=p;i++) vis[i]=0,dep[i]=inf,cur[i]=g[i]; Q.push(s),vis[s]=1,dep[s]=0; while(Q.size()){ int x=Q.front(); Q.pop(); vis[x]=0; for(int i=g[x];i;i=e[i].nex){ int to=e[i].adj,d=e[i].r; if(e[i].fw&&dep[to]>dep[x]+d){ dep[to]=dep[x]+d; if(!vis[to]){ vis[to]=1; Q.push(to); } } } } return dep[t]!=inf; } int dfs(int x,int F){ // puts("dfs"); if(!F||x==t) return F; int flow=0,f; vis[x]=1; for(int i=cur[x];i;i=e[i].nex){ int to=e[i].adj; cur[x]=i; if(!vis[to]&&dep[x]+e[i].r==dep[to]&& (f=dfs(to,min(F,e[i].fw)))>0){ e[i].fw-=f; e[i^1].fw+=f; flow+=f,F-=f; if(!F){ vis[x]=0; break; } } } return flow; } int P(int x,int y){return (x-1)*m+y;} //点序 int tx[]={-1,1,0,0,-1,-1,1,1}; int ty[]={0,0,-1,1,1,-1,1,-1}; //八向 int Ss[25][25],Ts[25][25]; //初始,终局 int main(){ scanf("%d%d",&n,&m); p=t=2*n*m+2,s=t-1; char c[25]; for(int i=1;i<=n;i++){ scanf("%s",c); for(int j=1;j<=m;j++) if(c[j-1]=='1') Ss[i][j]=1,S++; } for(int i=1;i<=n;i++){ scanf("%s",c); for(int j=1;j<=m;j++) if(c[j-1]=='1') Ts[i][j]=1,T++; } if(S!=T) return puts("-1"),0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(Ss[i][j]&&!Ts[i][j]) Add(s,P(i,j),1,0),fans++; //2 if(!Ss[i][j]&&Ts[i][j]) Add(P(i,j)+n*m,t,1,0); //3 } } for(int i=1,x;i<=n;i++){ scanf("%s",c); for(int j=1;j<=m;j++){ x=c[j-1]-'0'; Add(P(i,j),P(i,j)+n*m,x>>1,0); //4 if((Ss[i][j]^Ts[i][j])&&(x&1)) Add(P(i,j),P(i,j)+n*m,1,0); //※ for(int k=0;k<8;k++){ int xt=i+tx[k],yt=j+ty[k]; if(xt<1||xt>n||yt<1||yt>m) continue; Add(P(i,j)+n*m,P(xt,yt),inf,1); //5 } } } while(spfa()){ int d=dfs(s,inf); fans-=d; cans+=d*dep[t]; } if(fans) puts("-1"); else printf("%d\n",cans); return 0; }图是手画的,写题解不易。
关注博主,为文章点赞是你应该做的。
谢谢大家! !
- 1
信息
- ID
- 2232
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者