Asa comes up with a chess problem. There are N×N chesses on a board with N×N grids, one chess in one grid. Some chesses are black while others are white.
The N×N grids are divided into (N×N) / 2 pairs(N is even), and each grid only belongs to one pair. The two grids of a pair are in the same row or the same column. We can swap the chesses in a pair of grids. Suppose the number of black chesses in row i is R[i], and the number of black chesses in column j is C[j]. The problem is whether there is a solution satisfy that Rl[i] <= R[i] <= Rh[i] and Cl[j] <= C[j] <= Ch[j]. Rl[i], Rh[i], Cl[j] and Ch[j] are constant integers.
Please calculate the minimum number of swaps Asa needed to make the chess board satisfy the restriction.
最多 100 组样例
2≤N≤50
有源汇的上下界最小费用流。
首先构造有上下界的图,定义源点 S 和 汇点 T 。
此时问题可以看作求有源汇的上下界费用流求 S→T 流量为总黑子个数的最小费用。
求解有源汇上下界费用流可转换为求无源汇上下界最小费用可行循环流,通过 T→S 连边,流量上下界为 总黑子个数, INF 。
求解无源汇上下界最小费用可行循环流,重新构图:
做从 supS→supT 的最小费用流,限定到达 supT 的流量为满流(即 supS 所有出边的流量和)。此即为答案。
HINT: 原图中所有未提及的边费用都应记为 0 。新图中的重新构造的边的费用等同原图中对应边的费用。
#include
using namespace std;
const int N = 50 + 10;
int n, chs[N][N], rl[N], rh[N], cl[N], ch[N], r[N], c[N], s, t, sups, supt, digflow;
const int maxv = 100 + 10; //最大顶点数
const int inf = 2e9; //应大于总费用和
typedef pair<int, int> P; //first保存最短距离,second保存顶点编号
struct Edge{ int to,cap,rev, cost;}e;
vector g[maxv]; //图的邻接表表示
int h[maxv],dist[maxv]; //顶点的势、最短距离,若cost为整数,改INT
int prevv[maxv],preve[maxv],V;//最短路中的前驱节点、对应的边、顶点数
void addedge(int from, int to, int cap, int cost) { //加边
e.to = to, e.cap = cap, e.rev = g[to].size(), e.cost = cost;
g[from].push_back(e);
e.to = from, e.cap = 0, e.rev = g[from].size() - 1, e.cost = -cost;
g[to].push_back(e);
}
void addedge(int from, int to, int low, int up, int cost) {
digflow += low;
addedge(sups, to, low, cost);
addedge(from, supt, low, cost);
addedge(from, to, up-low, cost);
}
int mincostflow(int s,int t,int f) { //求解从s到t,流量为f的最小费用流
int res = 0;
memset(h,0,sizeof(4*t+4));
while(f>0) {
priority_queuevector
, greater
> que;
fill(dist,dist+V,inf);
dist[s] = 0;
que.push(P(0,s));
while(!que.empty()) {
P p = que.top(); que.pop();
int v = p.second;
if(dist[v] < p.first) continue;
for(int i=0;iif(E.cap > 0 && dist[E.to] > dist[v] + E.cost + h[v] - h[E.to]) {
dist[E.to] = dist[v] + E.cost + h[v] - h[E.to];
prevv[E.to] = v;
preve[E.to] = i;
que.push(P(dist[E.to],E.to));
}
}
}
if(dist[t] == inf) return -1;
for(int v = 0;v < V;v++) h[v] += dist[v];
//沿s到t的最短路尽量增广
int d = f;
for(int v = t;v!=s;v=prevv[v])
d = min(d,g[prevv[v]][preve[v]].cap);
f -= d;
res += h[t] * d;
for(int v = t;v!=s;v=prevv[v]) {
Edge &E = g[prevv[v]][preve[v]];
E.cap -= d;
g[v][E.rev].cap += d;
}
}
return res;
}
int main()
{
while(scanf("%d", &n)!=EOF)
{
digflow = 0;
s = 2*n + 1; sups = 0;
t = 2*n + 2; supt = 2*n+3;
memset(c, 0, sizeof(c));
memset(h, 0, sizeof(h));
for(int i=0;i<=supt;i++)
g[i].clear();
int mx = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d", &chs[i][j]);
c[j] += chs[i][j];
h[i] += chs[i][j];
mx += chs[i][j];
}
for(int i=1;i<=n;i++)
{
addedge(s, i, h[i], h[i], 0);
addedge(s, i+n, c[i], c[i], 0);
}
for(int i=1;i<=n;i++)
{
scanf("%d %d", &rl[i], &rh[i]);
addedge(i, t, rl[i], rh[i], 0);
}
for(int i=1;i<=n;i++)
{
scanf("%d %d", &cl[i], &ch[i]);
addedge(i+n, t, cl[i], ch[i], 0);
}
for(int i=1, x1, y1, x2, y2;i<=n*n/2;i++)
{
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
if(chs[x1][y1] == chs[x2][y2]) continue;
if(chs[x1][y1] == 0) swap(x1, x2), swap(y1, y2);
if(x1 == x2) {
addedge(n+y1, n+y2, 1, 1);
} else {
addedge(x1, x2, 1, 1);
}
}
addedge(t, s, mx, inf, 0);
V = 2*n+4;
int ans = mincostflow(sups, supt, digflow);
printf("%d\n", ans);
}
}