问题 A: 棋盘V
时间限制: 1 Sec 内存限制: 128 MB提交: 192 解决: 7
题目描述
有一块棋盘,棋盘的边长为100000,行和列的编号为1到100000。棋盘上有n个特殊格子,任意两个格子的位置都不相同。
现在小K要猜哪些格子是特殊格子。她知道所有格子的横坐标和纵坐标,但并不知道对应关系。换言之,她只有两个数组,一个存下了所有格子的横坐标,另一个存下了所有格子的纵坐标,而且两个数组都打乱了顺序。当然,小K猜的n个格子的位置也必须都不相同。
请求出一个最大的k,使得无论小K怎么猜,都能猜对至少k个格子的位置。
现在小K要猜哪些格子是特殊格子。她知道所有格子的横坐标和纵坐标,但并不知道对应关系。换言之,她只有两个数组,一个存下了所有格子的横坐标,另一个存下了所有格子的纵坐标,而且两个数组都打乱了顺序。当然,小K猜的n个格子的位置也必须都不相同。
请求出一个最大的k,使得无论小K怎么猜,都能猜对至少k个格子的位置。
输入
输入数据第一行包含一个整数n。
接下来n行,每行描述一个特殊格子的位置。第i行含有两个整数xi和yi ,代表第i个格子的坐标。保证任意两个格子的坐标都不相同。
接下来n行,每行描述一个特殊格子的位置。第i行含有两个整数xi和yi ,代表第i个格子的坐标。保证任意两个格子的坐标都不相同。
输出
输出一行,包含一个整数,代表最大的k。
样例输入
2
1 1
2 2
样例输出
0
提示
小K有可能会猜(1,2),(2,1),此时一个都没对
对于30%的数据,n≤8。
另外有5%的数据,所有横坐标和纵坐标均不相同。
另外有15%的数据,所有横坐标或者纵坐标均不相同。
对于100%的数据,n≤50,1≤xi,yi≤100000。
跑一遍最小费用最大流即可,把每一个坐标看作是"花费"为1的路径,分别从源点拉出路径到x做出"花费"为0,"流量"为cnt[x]的路径,从y到汇点拉出"花费"为0,"流量"为cnt[y]的路径。
#include <algorithm> #include <iostream> #include <cstring> #include <queue> #include <unordered_map> #include <set> using namespace std; #define N 10005 #define inf 0x3f3f3f3f struct E{ int to,next,val,cost; }; class graphic{ public: void clear(){ cnt = 0; res = 0; st = en = 0; memset(head,-1, sizeof(head)); } void add(int u,int v,int w,int c){ _add(u,v,w,c); _add(v,u,0,-c); } void setST(int a,int b){ st = a; en = b; } void Dinic(){ while (spfa())dfs(st,inf); } void show(){ cerr<<cnt<<endl; for(int i = 0 ; i < cnt ; ++i){ printf("%d %d ",i,edge[i].to); } cerr<<endl; } int ans(){ return res;} private: int st,en;///源点,汇点 int head[N]; int cnt; E edge[N]; bool spfaVis[N]; bool dfsVis[N]; int dis[N]; int res; void _add(int u,int v,int w,int c){ edge[cnt].to = v; edge[cnt].next = head[u]; edge[cnt].val = w; edge[cnt].cost = c; head[u] = cnt++; } bool spfa(){ memset(spfaVis,0, sizeof(spfaVis)); memset(dfsVis,0, sizeof(dfsVis)); queue<int>q; q.push(st); memset(dis,inf, sizeof(dis)); dis[st] = 0; spfaVis[st] = true; while (!q.empty()){ int u = q.front(); q.pop(); spfaVis[u] = false; for(int i = head[u],v ; ~i ; i = edge[i].next){ v = edge[i].to; if(edge[i].val and dis[v]>dis[u] + edge[i].cost){ dis[v] = dis[u] + edge[i].cost; if(!spfaVis[v]) { q.push(v); spfaVis[v] = true; } } } } return dis[en]<inf; } int dfs(int u,int f){ if(en==u){ res+=dis[en]*f; return f; } int ret = 0; dfsVis[u] = true; for(int i = head[u],v ; ~i ; i = edge[i].next){ v = edge[i].to; if(edge[i].val and !dfsVis[v] and dis[v] == dis[u] + edge[i].cost){ int temp = dfs(v,min(edge[i].val,f-ret)); edge[i].val-=temp; edge[i^1].val+=temp; ret+=temp; if(ret==f)return ret; } } return ret; } }; graphic ss; unordered_map<int,int>xx,yy;///坐标点到序号的映射 int cnt[N];///坐标出现次数 bool have[205][205]; set<int>sx,sy; int main(){ ss.clear(); int n,tolx,toly; scanf("%d",&n); tolx = 1,toly = n*2+1; int x,y; for(int i = 0 ; i < n ; ++i){ scanf("%d %d",&x,&y); if(!xx[x])xx[x] = tolx++; if(!yy[y])yy[y] = toly++; have[xx[x]][yy[y]] = true; ++cnt[xx[x]]; ++cnt[yy[y]]; sx.insert(xx[x]); sy.insert(yy[y]); } ss.setST(0,toly); for(auto &i: xx){ ss.add(0,i.second,cnt[i.second],0); } for(auto &i: yy){ ss.add(i.second,toly,cnt[i.second],0); } for(auto i:sx){ for(auto j:sy){ if(have[i][j]){ ss.add(i,j,1,1); } else ss.add(i,j,1,0); } } ss.Dinic(); cout<<ss.ans()<<endl; }