网络流练习题 猜测
猜测
【问题描述】
有一块棋盘,棋盘的边长为 100000,行和列的编号为 1 到 100000。棋盘上
有𝑛个特殊格子,任意两个格子的位置都不相同。
现在小 K 要猜哪些格子是特殊格子。她知道所有格子的横坐标和纵坐标,
但并不知道对应关系。换言之,她只有两个数组,一个存下了所有格子的横坐标,
另一个存下了所有格子的纵坐标,而且两个数组都打乱了顺序。当然,小 K 猜
的𝑛个格子的位置也必须都不相同。
请求出一个最大的𝑘,使得无论小 K 怎么猜,都能猜对至少𝑘个格子的位置。
【输入格式】
输入数据第一行包含一个整数𝑛。
接下来𝑛行,每行描述一个特殊格子的位置。第𝑖行含有两个整数𝑥 ( 和𝑦 𝑖 ,代
表第𝑖个格子的坐标。保证任意两个格子的坐标都不相同。
【输出格式】
输出一行,包含一个整数,代表最大的𝑘。
【样例输入 1】
2
1 1
2 2
【样例输出 1】
0
【样例解释 1】
小 K 有可能会猜(1,2),(2,1),此时一个都没对。
【样例输入 2】
3
1 1
1 2
2 1
【样例输出 2】
3
【样例解释 2】
此时只有一种合法的猜测。注意(1,1),(1,1),(2,2)不是一个合法的猜测。
【数据规模和约定】
对于 30%的数据,𝑛 ≤ 8。
另外有 5%的数据,所有横坐标和纵坐标均不相同。
另外有 15%的数据,所有横坐标或者纵坐标均不相同。
对于 100%的数据,𝑛 ≤ 50,1 ≤ 𝑥i,𝑦i ≤ 100000。
分析:将横坐标和纵坐标匹配,很容易就能看出这道题要用费用流来求解.
任意一对点的坐标都不相同,并且横坐标的值的数量和纵坐标的值的数量是固定的. 这些都可以通过边的容量来限制.
坐标比较大,需要先离散化,在值域上跑最小费用最大流.
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <algorithm> using namespace std; const int maxn = 100010,inf = 0x7fffffff; int n,sum1[maxn],sum2[maxn],a[maxn],b[maxn],c[maxn],cnt,flag[1010][1010]; int S,T,ans,vis[maxn],vis2[maxn],d[maxn],head[maxn],to[maxn],nextt[maxn],w[maxn],cost[maxn],tot = 2; void add(int x,int y,int z,int p) { cost[tot] = p; w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; cost[tot] = -p; w[tot] = 0; to[tot] = x; nextt[tot] = head[y]; head[y] = tot++; } bool spfa() { memset(vis,0,sizeof(vis)); memset(vis2,0,sizeof(vis2)); for (int i = 1; i <= T; i++) d[i] = inf; queue <int> q; q.push(S); d[S] = 0; vis[S] = 1; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && d[v] > d[u] + cost[i]) { d[v] = d[u] + cost[i]; if (!vis[v]) { vis[v] = 1; q.push(v); } } } } return d[T] < inf; } int dfs(int u,int f) { if (u == T) { ans += d[u] * f; return f; } int res = 0; vis2[u] = 1; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && !vis2[v] && d[v] == d[u] + cost[i]) { int temp = dfs(v,min(f - res,w[i])); w[i] -= temp; w[i ^ 1] += temp; res += temp; if (res == f) return res; } } return res; } void dinic() { while (spfa()) dfs(S,inf); } int main() { scanf("%d",&n); S = 4 * n + 1; T = S + 1; for (int i = 1; i <= n; i++) { scanf("%d%d",&a[i],&b[i]); c[++cnt] = a[i]; c[++cnt] = b[i]; } sort(c + 1,c + 1 + cnt); cnt = unique(c + 1,c + 1 + cnt) - c - 1; for (int i = 1; i <= n; i++) { a[i] = lower_bound(c + 1,c + 1 + cnt,a[i]) - c; b[i] = lower_bound(c + 1,c + 1 + cnt,b[i]) - c; sum1[a[i]]++; sum2[b[i]]++; flag[a[i]][b[i]] = 1; } for (int i = 1; i <= cnt; i++) { if (sum1[i]) add(S,i,sum1[i],0); if (sum2[i]) add(i + 2 * n,T,sum2[i],0); } for (int i = 1; i <= cnt; i++) for (int j = 1; j <= cnt; j++) { if (flag[i][j]) add(i,j + 2 * n,1,1); else add(i,j + 2 * n,1,0); } dinic(); printf("%d\n",ans); return 0; }