P3159 [CQOI2012]交换棋子
题意:
把这题作为费用流入门题真的会自闭
有误请指出,谢谢~
正解: 首先可以把白棋当作空白区域,从起始位置到最终位置可以看成是若干黑色棋子的移动,并且每个格子有访问次数限制。可以把限制作为流量,每次的交换形似花费,这时候就能想到要用费用流了 。
首先考虑不拆点的做法,把棋盘每相邻的两个建立一条边,但是这样的话每个格子的访问次数限制就没法体现了,没有办法统计从四面八方经过的黑色棋子。
这时候考虑拆成两个点的做法。可以想到,除了起点和终点每次经过是访问一次,路径上的点访问次数都是两次。这样做确实也没问题,就是把每个点的流量设置为每个格子的限制,黑棋的起点和终点花费设置为1,其他的点设为2。
更好理解的做法是拆成三个点,访问次数限制转化为流量的时候三个点中的两条边均摊流量,花费是0,针对连到两个格子间的边流量设为无穷大,花费为1,最后算在这样的流量限制下能跑到的最小花费。具体细节看代码:
#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint register int
#define oo 1e5
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
int f = 1; res = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0'; c = getchar(); }
res *= f;
}
const int ne[8][2] = {
1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1