【bzoj2668】[cqoi2012]交换棋子 费用流
题目描述
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。
输入
第一行包含两个整数n,m(1<=n, m<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。
输出
输出仅一行,为最小交换总次数。如果无解,输出-1。
样例输入
3 3
110
000
001
000
110
100
222
222
222
样例输出
4
题解
费用流
设 ai,j=[(i,j)原来为白色] ,bi,j=[(i,j)后来为白色] 。
显然可以只考虑白点的移动,转化为费用流问题:
S 向 ai,j=1 的点连边,容量为1,费用为0;bi,j=1 的点向T连边,容量为1,费用为0;相邻的点之间互相连边,容量为inf,费用为1。最小费用最大流即为答案。
但是这样有一个问题:给定的度数限制是入度+出度的限制,而不是分别的限制,这样无法直接拆点限制度数。
考虑,对于一个点,除去可能存在的 S 到其的入边 及 其到 T 的出边 以外,其它的一定入度=出度。因此入度就是 ⌊mi,j−ai,j−bi,j2⌋+bi,j=⌊mi,j−ai,j+bi,j2⌋ ,出度同理。
这样就能够求出一个点具体的入度出度限制,把一个点拆成3个:入点、中间点和出点。入点向中间点连边,容量为入度;中间点向出点连边,容量为出度。这样就限制了度数。
时间复杂度 O(费用流)
注意题目中的“连通”指的是八连通(一开始当成四连通卡了好久。。。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #include <queue> #include <cstdio> #include <cstring> #define N 1210 #define M 121000 #define inf 1 << 30 #define pos(i , j , k) (k * n * m + (i - 1) * m + j) using namespace std; queue< int > q; int a[25][25] , b[25][25] , c[25][25] , head[N] , to[M] , val[M] , cost[M] , next[M] , cnt = 1 , s , t , dis[N] , from[N] , pre[N]; inline void add( int x , int y , int v , int c) { to[++cnt] = y , val[cnt] = v , cost[cnt] = c , next[cnt] = head[x] , head[x] = cnt; to[++cnt] = x , val[cnt] = 0 , cost[cnt] = -c , next[cnt] = head[y] , head[y] = cnt; } bool spfa() { int x , i; memset (from , -1 , sizeof (from)); memset (dis , 0x3f , sizeof (dis)); dis[s] = 0 , q.push(s); while (!q.empty()) { x = q.front() , q.pop(); for (i = head[x] ; i ; i = next[i]) if (val[i] && dis[to[i]] > dis[x] + cost[i]) dis[to[i]] = dis[x] + cost[i] , from[to[i]] = x , pre[to[i]] = i , q.push(to[i]); } return ~from[t]; } inline int rnum() { char ch = getchar (); while (ch < '0' || ch > '9' ) ch = getchar (); return ch ^ '0' ; } int main() { int n , m , i , j , sum1 = 0 , sum2 = 0 , ans = 0; scanf ( "%d%d" , &n , &m) , s = 0 , t = 3 * n * m + 1; for (i = 1 ; i <= n ; i ++ ) for (j = 1 ; j <= m ; j ++ ) a[i][j] = rnum(); for (i = 1 ; i <= n ; i ++ ) for (j = 1 ; j <= m ; j ++ ) b[i][j] = rnum(); for (i = 1 ; i <= n ; i ++ ) for (j = 1 ; j <= m ; j ++ ) c[i][j] = rnum(); for (i = 1 ; i <= n ; i ++ ) { for (j = 1 ; j <= m ; j ++ ) { if (!c[i][j] && a[i][j] != b[i][j]) { puts ( "-1" ); return 0; } add(pos(i , j , 0) , pos(i , j , 1) , (c[i][j] - a[i][j] + b[i][j]) >> 1 , 0); add(pos(i , j , 1) , pos(i , j , 2) , (c[i][j] + a[i][j] - b[i][j]) >> 1 , 0); if (a[i][j]) add(s , pos(i , j , 1) , 1 , 0) , sum1 ++ ; if (b[i][j]) add(pos(i , j , 1) , t , 1 , 0) , sum2 ++ ; if (i > 1) add(pos(i , j , 2) , pos(i - 1 , j , 0) , inf , 1); if (i < n) add(pos(i , j , 2) , pos(i + 1 , j , 0) , inf , 1); if (j > 1) add(pos(i , j , 2) , pos(i , j - 1 , 0) , inf , 1); if (j < m) add(pos(i , j , 2) , pos(i , j + 1 , 0) , inf , 1); if (i > 1 && j > 1) add(pos(i , j , 2) , pos(i - 1 , j - 1 , 0) , inf , 1); if (i > 1 && j < m) add(pos(i , j , 2) , pos(i - 1 , j + 1 , 0) , inf , 1); if (i < n && j > 1) add(pos(i , j , 2) , pos(i + 1 , j - 1 , 0) , inf , 1); if (i < n && j < m) add(pos(i , j , 2) , pos(i + 1 , j + 1 , 0) , inf , 1); } } if (sum1 != sum2) puts ( "-1" ); else { while (spfa()) { j = inf; for (i = t ; i != s ; i = from[i]) j = min(j , val[pre[i]]); sum1 -= j , ans += j * dis[t]; for (i = t ; i != s ; i = from[i]) val[pre[i]] -= j , val[pre[i] ^ 1] += j; } if (sum1) puts ( "-1" ); else printf ( "%d\n" , ans); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥
2017-01-18 【poj2104】K-th Number 主席树
2017-01-18 【bzoj3772】精神污染 STL+LCA+主席树
2017-01-18 【bzoj3932】[CQOI2015]任务查询系统 离散化+主席树