首页 > 其他分享 >upc 6445: 棋盘V (网络流费用流解决匹配问题)

upc 6445: 棋盘V (网络流费用流解决匹配问题)

时间:2023-05-29 11:31:51浏览次数:54  
标签:格子 int MAX flow upc 6445 坐标 棋盘 dis


6445: 棋盘V

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

【题意】

对于题意,应该理解为,小K尽量猜错。

对于给出的坐标x和y,完成一个一一匹配,使得匹配完成后,与原坐标重复的最少。

【分析】

貌似是一个带权二分图匹配问题,没试过KM算法是否可行。我用的费用流。

对输入的坐标离散化一下,方便建图。

枚举x坐标和y坐标,若(x,y)之间是正确边,则建边容量=1,费用=1;否则,建边容量=1,费用=0;

虚拟源点0,汇点maxver(一个很大的不存在的编号即可)

对0到所有的x坐标建边,容量为x行所含做标数,费用=0

对所有y到maxver建边,容量为y列所含做标数,费用=0;

对此图跑一遍费用流,按照费用流策略,优先走费用为0的边,即错误边,错误边满流时,不得不走正确边,花费1.

故最后的费用流即为不得不猜对的坐标。

【代码】

/****
***author: winter2121
****/
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define SI(i) scanf("%d",&i)
#define PI(i) printf("%d\n",i)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAX=4e2+5;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
int dir[9][2]={0,1,0,-1,1,0,-1,0, -1,-1,-1,1,1,-1,1,1};
template<class T>bool gmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>bool gmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>void gmod(T &a,T b){a=(a%mod+b)%mod;}




struct node{
    int s,t,len,cap,flow,next;
}e[MAX*MAX];//len路长,cap最大流量,flow已流的量
int head[MAX],cnt;
void add(int u,int v,int len,int cap,int flow=0)
{
    e[cnt]=node{u,v,len,cap,flow,head[u]};
    head[u]=cnt++;
}
int dis[MAX];//最短路
bool inq[MAX];
int f[MAX];//流量
int pre[MAX];//前驱边
bool spfa(int s,int t,int &flow,int &cost,int ver) //ver是最大点编号
{
    for(int i=0;i<=ver;i++)dis[i]=INF;
    memset(inq,0,sizeof(inq));
    dis[s]=0;f[s]=INF;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        inq[u]=0;
        for(int i=head[u];~i;i=e[i].next)
        {
            if(e[i].cap-e[i].flow>0&&dis[e[i].t]>dis[u]+e[i].len)   //只要有流量,并且路径变短
            {
                f[e[i].t]=min(f[u],e[i].cap-e[i].flow);
                dis[e[i].t]=dis[u]+e[i].len;
                pre[e[i].t]=i;
                if(!inq[e[i].t])
                    q.push(e[i].t),inq[e[i].t]=1;
            }
        }
    }
    if(dis[t]==INF) return 0;  //没走到终点
    flow+=f[t];  //本条增广路的流量
    cost+=dis[t]*f[t];  //花费
    for(int u=t;u!=s;u=e[pre[u]].s)
    {
        e[pre[u]].flow+=f[t];
        e[pre[u]^1].flow-=f[t];
    }
    return 1;
}
int mincost(int s,int t,int ver)
{
    int flow=0,cost=0;
    while(spfa(s,t,flow,cost,ver));
    return cost;
}

int n;
int cx[MAX],cy[MAX];
int x[MAX],y[MAX];
int hax[MAX],hay[MAX];
int mmp[100][100];
int main()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    SI(n);
    for(int i=1;i<=n;i++)
    {
        SI(x[i]);SI(y[i]);
        hax[i]=x[i],hay[i]=y[i];
    }
    sort(hax+1,hax+n+1);
    sort(hay+1,hay+n+1);
    int topx=unique(hax+1,hax+n+1)-hax-1;
    int topy=unique(hay+1,hay+n+1)-hay-1;
    rep(i,1,n)
    {
        int xx=lower_bound(hax+1,hax+1+topx,x[i])-hax;
        int yy=lower_bound(hay+1,hay+1+topy,y[i])-hay;
        cx[xx]++;
        cy[yy]++;
        mmp[xx][yy]=1;
    }
    rep(i,1,topx)
    {
        rep(j,1,topy)
        {
            add(i,j+topx,mmp[i][j],1);
            add(j+topx,i,-mmp[i][j],0);
            //cout<<xx<<' '<<yy<<' '<<(i==j)<<endl;
        }
    }
    rep(i,1,topx)
    {
        add(0,i,0,cx[i]);
        add(i,0,0,0);
    }
    rep(i,1,topy)
    {
        add(i+topx,topx+topy+1,0,cy[i]);
        add(topx+topy+1,i+topx,0,0);
    }
    ll ans=mincost(0,topx+topy+1,topx+topy+1);
    printf("%lld\n",ans);
}
/*
4
1 1
2 2
3 3
1 3
ans=1
5
1 1
2 2
3 3
4 4
1 4
ans=0
*/

 

标签:格子,int,MAX,flow,upc,6445,坐标,棋盘,dis
From: https://blog.51cto.com/u_16125110/6369263

相关文章

  • THUPC2023游记
    2023.2THUPC报名!和unputdownable,猫猬兽组队,队名XJ五队。devin让我们填毕业年份2028。收货地址填了重庆市第114514中学冯阳阳纪念谷学校。upd性别填其他被拒了。2023.3.4THUPC2023初赛测试赛!\(3\)月\(4\)日\(13\)点联络群消息:##OJ网址thupc2023.thusa......
  • P5446 [THUPC2018]绿绿和串串 题解
    Description给定一个串\(S\),要求串\(S\)是串\(R\)经过多次翻转后的前缀。问有多少种初始长度的串\(R\)。串\(R\)翻转的定义是将前\(|R|-1\)个字符倒序排列后,插入到串的最后。如\(\mathrm{aaa}\)翻转后得到\(\mathrm{abcdcba}\)。Solution我们先设以\(i\)为......
  • 刷题笔记:Luogu P3956 棋盘
    ProblemSolutionDFS/BFS需要注意去重的时候可以重复走(因为有限定条件),只要新的步数比原来的步数小就可以走,其余情况模拟即可细节有点多,比如需要记录一下上一步的棋盘颜色(下一次搜索传递参数),因为牵扯到使用魔法问题,不能直接染,因为改变地图后后边很多操作都会受影响在列举可能性......
  • 图解LeetCode——782. 变为棋盘(难度:困难)
    一、题目一个 n*n 的二维网络 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置。返回将这个矩阵变为 “棋盘”  所需的最小移动次数 。如果不存在可行的变换,输出-1。“棋盘”是指任意一格的上下左右四个方向的值均与本身不同的矩阵。二、示例......
  • CF213C (棋盘dp的经典例题)
    RelayRace-洛谷|计算机科学教育新生态(luogu.com.cn)本题是棋盘dp的经典例题。可以先转化一下题意:从(1,1)走两条路径到(n,n),再确保两人是同步行走的。我们可以让一人的走路范围一直在左下方向,一人的走路范围一直在右上方向。(倘若两人的路径交叉,则都可以转化成这种情况)令......
  • 2023 xjtupc 西交校赛
    A签到,\(O(1)\)。C++Code#include"bits/stdc++.h"usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);intn;cin>>n;cout<<(n<=6?"water"......
  • (hdu step 2.3.8)小兔的棋盘(卡特兰数:从左上角走到右上角的路径数)
    题目:     小兔的棋盘TimeLimit:1000/1000MS(Java/Others)MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):802AcceptedSubmission(s):502ProblemDescription小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是......
  • 1.棋盘问题(简单搜索)
    棋盘问题↑题目链接题目在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放\(k\)个棋子的所有可行的摆放方案数目\(C\)输入格式输入含有多组测试数据。......
  • P7603 [THUPC2021] 鬼街(减半警报器模板)
    P7603[THUPC2021]鬼街(减半警报器模板)前言这是一个由lxl大佬提出的神奇trick,第一次省选集训的时候有点颓,听完了没写。刚好明天又要讲这个不如写篇题解。还是,我太弱了;所以又是研究一晚上才写出来,所以还是吧我对这道题的理解讲讲。正文何为折半报警器按照lxl的ppt上的......
  • 棋盘覆盖问题——分治法
    问题描述有一个 x (k>0)的棋盘,恰好有一个方格与其他方格不同,称之为特殊方格。现在要用如下图所示的L形骨牌覆盖除了特殊方格以外的其他全部方格,骨牌可以任意旋转,并且任何两个骨牌不能重复。请给出一种覆盖方式。 样例:输入:输出: 思路——分治法:将一个规模为n的问题分解......