P3355 骑士共存问题 二分建图 + 当前弧优化dinic

P3355 骑士共存问题

题意:

  也是一个棋盘,规则是“马”不能相互打到。

思路:

  奇偶点分开,二分图建图,这道题要注意每个点可以跑八个方向,两边都可以跑,所以边 = 20 * n * n。

  然后dinic 要用当前弧优化。

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>

using namespace std;
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "\n";
#define pb push_back
#define pq priority_queue

typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 bll;
typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int,pii> p3;

//priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl ‘\n‘

#define OKC ios::sync_with_stdio(false);cin.tie(0)
#define FT(A,B,C) for(int A=B;A <= C;++A)  //用来压行
#define REP(i , j , k)  for(int i = j ; i <  k ; ++i)
#define max3(a,b,c) max(max(a,b), c);
#define min3(a,b,c) min(min(a,b), c);
//priority_queue<int ,vector<int>, greater<int> >que;

const ll oo = 1ll<<17;
const ll mos = 0x7FFFFFFF;  //2147483647
const ll nmos = 0x80000000;  //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f; //18
const int mod = 1000000007;
const double esp = 1e-8;
const double PI=acos(-1.0);
const double PHI=0.61803399;    //黄金分割点
const double tPHI=0.38196601;

template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘) f|=(ch==‘-‘),ch=getchar();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x=f?-x:x;
}
/*-----------------------showtime----------------------*/
            const int maxn = 209;
            int mp[maxn][maxn];

            struct E
            {
                int u,v,val;
                int nxt;
            }edge[20 * maxn*maxn];
            int gtot = 0,head[maxn*maxn];
            void addedge(int u,int v,int val){
                edge[gtot].u = u;
                edge[gtot].v = v;
                edge[gtot].val = val;
                edge[gtot].nxt = head[u];
                head[u] = gtot++;

                edge[gtot].u = v;
                edge[gtot].v = u;
                edge[gtot].val = 0;
                edge[gtot].nxt = head[v];
                head[v] = gtot++;
            }
            int nx[8][2] = {
                {-2,-1}, {-1,-2},{-2, 1},{-1,2},{1,-2},{2,-1},{1,2},{2,1}
            };
            int n,m;
            int cal(int i,int j){
                return (i-1)*n + j;
            }

            int dis[maxn*maxn],cur[maxn*maxn];
            bool bfs(int s,int t){
                memset(dis, inf, sizeof(dis));
                for(int i=s; i<=t; i++) cur[i] = head[i];
                queue<int>que;
                que.push(s);
                dis[s] = 0;
                while(!que.empty()){
                    int u = que.front(); que.pop();
                    for(int i= head[u]; ~i; i = edge[i].nxt){
                        int v = edge[i].v;
                        if(edge[i].val > 0 && dis[v] > dis[u] + 1){
                            dis[v] = dis[u] + 1;
                            que.push(v);
                        }
                    }
                }
                return dis[t] < inf;
            }

            int dfs(int u,int t,int maxflow){
                if(u == t || maxflow == 0) return maxflow;

                for(int i=cur[u]; ~i; i = edge[i].nxt){
                    cur[u] = i;
                    int v = edge[i].v;
                    if(edge[i].val > 0 && dis[v] == dis[u] + 1){
                        int f = dfs(v, t, min(maxflow, edge[i].val));

                        if(f > 0){
                            edge[i].val -= f;
                            edge[i^1].val += f;
                            return f;
                        }
                    }

                }
                return 0;
            }
            int dinic(int s,int t){
                int flow = 0;
                while(bfs(s,t)){
                    while(int f = dfs(s,t,inf)) flow += f;
                }
                return flow;
            }
int main(){
            memset(head, -1, sizeof(head));
            scanf("%d%d", &n, &m);
            int s = 0, t = n*n+1;
            int sum = n * n;
            for(int i=1; i<=m; i++){
                int x,y;
                scanf("%d%d", &x, &y);
                mp[x][y] = 1;
                sum--;
            }
            for(int i=1; i<=n; i++){
                for(int j=1; j<=n; j++) {
                    if((i+j)% 2 == 1) {
                        if(mp[i][j]) addedge(s, cal(i,j), 0);
                        else addedge(s, cal(i, j), 1);
                    }
                    else {
                        if(mp[i][j]) addedge(cal(i,j),t, 0);
                        else addedge(cal(i,j), t, 1);
                    }
                }
            }

            for(int i=1; i<=n; i++){
                for(int j=1; j<=n; j++){
                        if((i+j)% 2 == 0) continue;
                        for(int k=0; k<8; k++){
                            int x = i + nx[k][0];
                            int y = j + nx[k][1];
                            if(x <1 || x > n || y < 1 || y > n) continue;
                            addedge(cal(i,j), cal(x,y),inf);
                        }
                }
            }
            cout<<sum - dinic(s, t)<<endl;
            return 0;
}

原文地址:https://www.cnblogs.com/ckxkexing/p/10351814.html

时间: 2024-10-12 23:42:20

P3355 骑士共存问题 二分建图 + 当前弧优化dinic的相关文章

P3355 骑士共存问题 网络流

骑士共存 题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击 输入输出格式 输入格式: 第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数.接下来的 m 行给出障碍的位置.每行 2 个正整数,表示障碍的方格坐标. 输出格式: 将计算出的共存骑士数输出

POJ 2112 最大流+二分+(建图:最重要的)

Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 12521   Accepted: 4524 Case Time Limit: 1000MS Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) co

P3355 骑士共存问题

二分图最大独立集 先给出二分图最大独立集的概念:选择最多的点,使任何边的两边不被同时选中. 并且有结论:最大独立集=节点总数-最大匹配. 这道题为什么是二分图? 我们可以通过\((x,y)\)中的\(x+y\)的奇偶性来构造二分图,显然它们肯定不会互相攻击. 当一个点\(x+y\)为奇时,向它能攻击到的点都连一条权值为1的边. 这就是这个二分图的建图方法. 但是我不会匈牙利算法,直接网络流套下去就行了. 注意:那些障碍点对我们整个计算根本没有影响,直接忽略它们就可以了.节点总数也不用计算它们.

「CODVES 1922 」骑士共存问题(二分图的最大独立集|网络流)&amp;dinic

首先是题目链接  http://codevs.cn/problem/1922/ 结果发现题目没图(心情复杂 然后去网上扒了一张图 大概就是这样了. 如果把每个点和它可以攻击的点连一条边,那问题就变成了求二分图的最大独立集了 (二分图最大独立集:即一个点集,集合中任两个结点不相邻),然后就是建图了. 题图非常好心的帮忙染色了,所以我们可以看出来,一个点可以到达的点和它的颜色是不一样的,所以只需要黑白染色就可以了,然后把黑点看作一个集合, 白点看作一个集合,又因为二分图最大独立集= 二分图最大匹配,

洛谷 P3355 骑士共存问题

题目描述 在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入 对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击 输入输出格式 输入格式: 第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数.接下来的 m 行给出障碍的位置.每行 2 个正整数,表示障碍的方格坐标. 输出格式: 将计算出的共存骑士数输出 输入输出样

洛谷 P3355 骑士共存问题【最小割】

同方格取数问题:https://www.cnblogs.com/lokiii/p/8430720.html 记得把障碍点去掉,不连边也不计入sum #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=100005,inf=1e9,dx[]={-2,-1,1,2,2,1,-1,-2},dy[]={-1,-2,

luogu P3355 骑士共存问题

本题和方格取数一样,也可以分成黑白点,本题加上特判一个点是否有障碍即可,其余和那题没什么区别,挂一下大佬的证明(二分图最大独立集) #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x)&(-x)) typedef long long LL; const int maxm = 1e6+5; const int INF = 0x3f3f3f3f; const int dx[] = {-2,-2,-1,-1,1

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)

poj 2226 Muddy Fields(合理建图+二分匹配)

1 /* 2 题意:用木板盖住泥泞的地方,不能盖住草.木板任意长!可以重叠覆盖! '*'表示泥泞的地方,'.'表示草! 3 思路: 4 首先让我们回忆一下HDU 2119 Matrix这一道题,一个矩阵中只有0, 1,然后让我们通过选择一行,或者 5 是一列将其所在行的或者所在列的 1全部删掉,求出最少需要几步? 6 7 这道题的思路就是:将行标 和 列标值为1的建立一条边!通过匈牙利算法可以得到这个二分图的最大匹配数 8 最大匹配数==最小顶点覆盖数!最小顶点覆盖就是用最少的点覆盖了这个二分图