首页 > 其他分享 >P3355 骑士共存问题题解

P3355 骑士共存问题题解

时间:2024-01-25 11:56:02浏览次数:32  
标签:P3355 res jz int 题解 dep && 共存 hd

题目链接:P3355 骑士共存问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题解:

棋盘问题考虑黑白染色成为二分图后做。

观察马的性质,可知一个点只能到一个异色点,所以,构造方案可以先将所有同色点放上马,再考虑有那些异色点不可以放置。

方法一:

网络流,时间复杂度为O(|E|min(|E|0.5,|V|0.3))

从源点向每个白点连一条限制为1的边(黑色,白色都可以我选定先在白色放满马)(这里的1没有太大的意义,可以理解为每个点一匹马)

从白点向与它不可共存的点,连边,限制为1因为流量最大为1。

从黑点向汇点连一条限制为1的边。

最后答案为n*n-m-ans,表示总点数减去障碍点,再减去冲突的黑点。

#include <bits/stdc++.h>
using namespace std;
const int N=50010; 
const int M=500010;
int tot=1,n,m,s,t,nxt[M],go[M],hd[N],dep[N],cur[N],vis[N],jz[M],ans;
queue<int> q;
bool bfs()
{
       memset(dep,0,sizeof(dep));
       memcpy(cur,hd,sizeof(hd));
       q.push(s);
       dep[s]=1;
       while(!q.empty())
       {
              int u=q.front();
              q.pop();
              for(int i=hd[u];i;i=nxt[i])
               {
                        int v=go[i];
                        if(!jz[i]||dep[v])continue;
                        dep[v]=dep[u]+1;
                        q.push(v);
               }
       }
       return dep[t];
}
int dfs(int u,int flow)
{
       if(u==t)return flow;
       int out=0;
       for(int i=cur[u];i&&flow;i=nxt[i])
       {
                   cur[u]=i;
               int v=go[i];
               if(jz[i]&&dep[v]==dep[u]+1)
               {
                        int res=dfs(v,min(jz[i],flow));
                        if(res)
                        {
                                 jz[i]-=res;jz[i^1]+=res;flow-=res;out+=res;
                        }
               }
       }
       if(out==0) dep[u]=0;
       return out;
}
void add(int u,int v,int w)
{
       nxt[++tot]=hd[u];
       hd[u]=tot;
       go[tot]=v;
       jz[tot]=w;
}
int id(int x,int y)
{
    return (x-1)*n+y;
}
int xj[10]={2,2,-2,-2,1,1,-1,-1};
int yj[10]={1,-1,1,-1,2,-2,2,-2};
int main()
{
       scanf("%d%d",&n,&m);
       s=0,t=n*n+1; 
       for(int i=1;i<=m;i++)
       {
            int x,y;
            scanf("%d%d",&x,&y);
            vis[id(x,y)]=1;
       }
       for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                int ids=id(i,j);
                if(vis[ids])continue;
                if((i+j)%2==0)
                {
                    add(s,ids,1);
                    add(ids,s,0);
                    for(int k=0;k<8;k++)
                    {
                        int x=i+xj[k];
                        int y=j+yj[k];
                        if(x>0&&y>0&&x<=n&&y<=n&&vis[id(x,y)]==0)
                        {
                            add(ids,id(x,y),1e9);
                            add(id(x,y),ids,0);
                        } 
                    }
                }
                else
                {
                    add(ids,t,1);
                    add(t,ids,0);
                }
            }
        while(bfs())
        ans+=dfs(s,1e9);
        printf("%lld\n",n*n-m-ans);
        return 0;
}

方法二:
匈牙利算法。

从白点向限制的黑点连边,跑匈牙利,求最大匹配。

但是加了一个数据,匈牙利跑不过去,所以二分图的问题,最好转成网络流来做,更快。

#include <iostream>
#include <cstdio>
#include <cstring> 
using namespace std;
const int N=50010; 
const int M=500010;
int tot,n,m,nxt[M],go[M],hd[N],girl[N],ans,wz[210][210];
bool bk[N],vis[N];
int xj[10]={2,2,-2,-2,1,1,-1,-1};
int yj[10]={1,-1,1,-1,2,-2,2,-2};
inline int read(){
    int ans=0;char c;bool flag=true;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')flag=false;
    for(;c>='0'&&c<='9';c=getchar())ans=ans*10+c-'0';
    return flag ? ans : -ans;
}
inline void add(int x,int y)
{
    nxt[++tot]=hd[x];go[tot]=y;hd[x]=tot;
    return ;
}
inline bool find(int x)
{
    for(int i=hd[x];i;i=nxt[i])
    {
        int y=go[i];
        if(vis[y])continue;
        vis[y]=1;
        if(!girl[y]||find(girl[y]))
        {
            girl[y]=x;
            return 1;
        }
    }
    return 0;
}
inline int id(int x,int y)
{
    return (x-1)*n+y;
 } 
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x,y;
        x=read(),y=read();
        bk[id(x,y)]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            wz[i][j]=id(i,j);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if(bk[wz[i][j]])continue;
            if((i+j)%2)
                for(int k=0;k<8;k++)
                {
                    int x=i+xj[k];
                    int y=j+yj[k];
                    if(x>0&&y>0&&x<=n&&y<=n&&bk[wz[x][y]]==0)
                        add(wz[i][j],wz[x][y]);                
                }
            
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if((i+j)%2&&!bk[wz[i][j]])
            {
                memset(vis,0,sizeof(vis));
                if(find(wz[i][j]))ans++;
            }        
    printf("%d\n",n*n-m-ans);
    return 0;
}

 

 

    

标签:P3355,res,jz,int,题解,dep,&&,共存,hd
From: https://www.cnblogs.com/storms11/p/17986861

相关文章

  • P7900 [COCI2006-2007#2] SJECIŠTA_题解
    [COCI2006-2007#2]SJECIŠTA_题解rt我们来看一下题目描述考虑一个有$n$个顶点的凸多边形,且这个多边形没有任何三个(或以上)的对角线交于一点。这句话什么意思?当顶点为$n$的图形为正多边形时便有可能出现一个点是有三条线相交而构成的如图如图情况就有三个......
  • P9779_[HUSTFC 2023] 不定项选择题_题解
    rt题目有一道共n个选项的不定项选择题,它的答案至少包含一个选项,由于题目与选项的内容晦涩难懂,你打算通过尝试每一种可能的答案来通过这道题。初始时所有选项都没有被勾选,你可以执行任意次下述操作:勾选一个当前未被勾选的选项。取消勾选一个当前已被勾选的选项。当你......
  • P2045 方格取数加强版题解
    题目链接:P2045方格取数加强版-洛谷|计算机科学教育新生态(luogu.com.cn)题目:出一个n*n的矩阵,每一格有一个非负整数A{i,j}且A{i,j} <=10^3现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要......
  • CF349B Color the Fence 题解 贪心
    贪心题意:你一共有\(v\)元,给你数字\(1\)~\(9\)的价值,求出你能够买下的数字组成的最大数。思路首先,我们知道能够买下的数字个数越多,组成数字的位数就越多,结果自然就越大,那么,根据贪心策略,我们可以先全买价格最便宜的数字(相同价格时,自然买更大的)。参考代码:intv;cin>>v;......
  • CF467C George and Job 题解 DP 前缀和
    DP前缀和题目链接题意:给你一个长度为\(n\)的序列,让你从这个序列中挑选出\(k\)个长度为\(m\)的区间,并且任意区间不相交。使得选出的数之和最大,求出这个数。解法:很经典的DP模型,我们定义\(f_{i,j}\)表示从前\(i\)个数选出了\(j\)个区间可以取得的最大值,那么答案为:\(f_{n,k}\)。......
  • SNOI 2024 题解(坑:D1T3 D2T1 D2T2)
    树V图相同\(f(i)\)的点必然构成一个连通块,不然一定无解。每一个连通块中需要选出一个关键点,考虑相邻连通块是否合法,发现条件其实很很好判,就是两个交界点的距离需要满足某个大小关系,容易预处理后\(O(1)\)判,于是\(f_{u,x}\)表示\(u\)连通块内取\(x\)的方案数,DP即可。......
  • 关于php进行post出现500的超时问题解决办法
      最近搞个项目使用php进行post请求,时间长了就会出现500错误,ngnix报了个错误:upstreamtimedout(10060:Aconnectionattemptfailedbecausetheconnectedpartydidnotproperlyrespondafteraperiodoftime,orestablishedconnectionfailedbecauseconnected......
  • P1481魔族密码 题解(字典树)
    魔族密码题目背景风之子刚走进他的考场,就……花花:当当当当~~偶是魅力女皇——花花!!^^(华丽出场,礼炮,鲜花)风之子:我呕……(杀死人的眼神)快说题目!否则……-_-###题目描述花花:……咦好冷我们现在要解决的是魔族的密码问题(自我陶醉:搞不好魔族里面还会有人用密码给我和菜虫写情书咧,哦......
  • 【题解 P8575】 星之河
    「DTOI-2」星之河题目背景星稀河影转,霜重月华孤。题目描述星之统治者有一个星盘,其可以被抽象为一棵根节点为\(1\)的树。树上每个节点\(i\)有一颗红星、一颗蓝星,亮度分别记为\(\text{Red}_i,\text{Blue}_i\)。现在,星之统治者想要知道,对于每个节点\(x\),其子树内(不包括......
  • 题解 P9911 [COCI 2023/2024 #2] Kuglice
    传送门。题意应该是显然的.分析首先,观察数据范围:\(1\len\le3000\),也就是说,时间复杂度应当在\(O(n^2)\)左右。其次,观察我们取球的顺序,是只能从左或右取,因此,我们每次留下的必然是连续的一段。所以,我们显然可以采用区间DP来解决这道题。确定状态:\(f_{i,j}\)表示现在取......