棋盘V(最小费用最大流)

                                                            棋盘V

                                                             时间限制: 1 Sec  内存限制: 128 MB
                                                                          提交: 327  解决: 33
                                                             [提交] [状态] [讨论版] [命题人: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。

来源/分类

中山纪念中学20170301 

题意:

给你n对坐标,但是这里的x和y不一定原来匹配的,让你求他最少能猜对几个(在最坏的情况下能才对几个:无论怎么猜都会对几个),并且猜的对中没有一样的

题解;

刚开始想着贪心,枚举情况,后来发现情况太多 ,赛后补题,题解里用的网络流还有二分图最大匹配,我这里用的是最小费用最大流,如何见图是关键,我们将超级源点和每个互不相同的x进行连线,容量是x出现的次数,费用是零,让每个不相同的y和超级汇点连接,容量为y出现的次数,费用为零,假设给出的x,y对是唯一匹配的,(事实上不一定这个x就是配这个y的),将匹配的连线,费用为一,容量为1,x和不匹配的y也连线,只不过费用为0,容量依然为1,见图完毕

这里要注意的是,超级源点和超级汇点不能为负数,因为数组下标是0——n-1的。注意这两个点的值不能和中间的点的值重复,中间的点的标号也不能相同。

代码:

这里的最小费用最大流的板子来自其他博客,但是忘记是哪个了,如果板子的主人看到了,欢迎来认领

#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include<map>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define MAXN 100003
#define MAXM 80000+100
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, cap, flow, cost, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int pre[MAXN];//记录增广路径上 到达点i的边的编号
int dist[MAXN];
bool vis[MAXN];
int N, M;//点数 边数
int source, sink;//超级源点 超级汇点
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int w, int c)
{
    Edge E1 = {u, v, w, 0, c, head[u]};
    edge[edgenum] = E1;
    head[u] = edgenum++;
    Edge E2 = {v, u, 0, 0, -c, head[v]};
    edge[edgenum] = E2;
    head[v] = edgenum++;
}
bool SPFA(int s, int t)//寻找花销最少的路径
{
    //跑一遍SPFA 找s——t的最少花销路径 且该路径上每一条边不能满流
    //若存在 说明可以继续增广,反之不能
    queue<int> Q;
    memset(dist, INF, sizeof(dist));
    memset(vis, false, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    dist[s] = 0;
    vis[s] = true;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            Edge E = edge[i];
            if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow)//可以松弛 且 没有满流
            {
                dist[E.to] = dist[u] + E.cost;
                pre[E.to] = i;//记录前驱边 的编号
                if(!vis[E.to])
                {
                    vis[E.to] = true;
                    Q.push(E.to);
                }
            }
        }
    }
    return pre[t] != -1;//可达返回true
}
void  MCMF(int s, int t, int &cost, int &flow)
{
    flow = 0;//总流量
    cost = 0;//总费用
    while(SPFA(s, t))//每次寻找花销最小的路径
    {
        int Min = INF;
        //通过反向弧 在源点到汇点的最少花费路径 找最小增广流
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            Edge E = edge[i];
            Min = min(Min, E.cap - E.flow);
        }
        //增广
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            edge[i].flow += Min;
            edge[i^1].flow -= Min;
            cost += edge[i].cost * Min;//增广流的花销
        }
        flow += Min;//总流量累加
    }
   return ;
}
/********************板子到此结束,以上为最小费用最大流的模板*********************/
int flag[300][300];
int main()
{
    int n;
    while(~scanf("%d",&n))
    { init();
        int x[1005],y[1005];
        int z[1005]={0};
        int u=0;
        memset(flag,0,sizeof(flag));
        for(int i=0; i<n; i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            z[u++]=x[i];
            z[u++]=y[i];
        }
       // printf("%d%d\n",xx[x1[0]],y5[0]);
       sort(z,z+u);
       int len=unique(z,z+u)-z;
       int cx[1005]={0};
       int cy[1005]={0};
       for(int i=0;i<n;i++)
       {
           x[i]=lower_bound(z,z+len,x[i])-z+1;
           y[i]=lower_bound(z,z+len,y[i])-z+1;
           cx[x[i]]++;
           cy[y[i]]++;
           flag[x[i]][y[i]]=1;
       }
source=0; sink=2*len+1;
       for(int i=1; i<=len; i++)
       {
            if(cx[i]) addEdge(source,i,cx[i],0);
            if(cy[i]) addEdge(i+len,sink,cy[i],0);
       }
       for(int i=1;i<=len;i++)
       {
           for(int j=1;j<=len;j++)
           {
               if(flag[i][j])addEdge(i,j+len,1,1);
               else  addEdge(i,j+len,1,0);
           }
       }
        int cost, flow;//最小费用 最大流
        MCMF(source, sink, cost, flow);
 
        printf("%d\n",cost) ;
    }
}

猜你喜欢

转载自blog.csdn.net/wrwhahah/article/details/81388729