网络流:棋盘V

问题 A: 棋盘V

时间限制: 1 Sec  内存限制: 128 MB
提交: 192  解决: 7

[提交] [状态] [讨论版] [命题人:admin]
题目描述
有一块棋盘,棋盘的边长为100000,行和列的编号为1到100000。棋盘上有n个特殊格子,任意两个格子的位置都不相同。
现在小K要猜哪些格子是特殊格子。她知道所有格子的横坐标和纵坐标,但并不知道对应关系。换言之,她只有两个数组,一个存下了所有格子的横坐标,另一个存下了所有格子的纵坐标,而且两个数组都打乱了顺序。当然,小K猜的n个格子的位置也必须都不相同。
请求出一个最大的k,使得无论小K怎么猜,都能猜对至少k个格子的位置。

 

输入
输入数据第一行包含一个整数n。
接下来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\n",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;
}

 

 

 

 

转载于:https://www.cnblogs.com/DevilInChina/p/9396296.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值