luogu P2825 [HEOI2016/TJOI2016]游戏

题面

https://www.luogu.org/problemnew/show/P2825

题解

水题

二分图匹配的经典模型。

对于硬石头,拆点。

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#define ri register int
#define N 505000
#define INF 1000000007
#define T (n+m+1)

using namespace std;

int n,m,han[100][100],lie[100][100];
vector<int> to,w,ed[N];
int cur[N],d[N],tn,tm;
char g[100][100];

void add_edge(int u,int v,int w1,int w2) {
  to.push_back(v); w.push_back(w1); ed[u].push_back(to.size()-1);
  to.push_back(u); w.push_back(w2); ed[v].push_back(to.size()-1);
}

bool bfs() {
  queue<int> q;
  memset(d,0x3f,sizeof(d));
  d[0]=0; q.push(0);
  while (!q.empty()) {
    int x=q.front(); q.pop();
    for (ri i=0,l=ed[x].size();i<l;i++) {
      int e=ed[x][i];
      if (w[e] && d[x]+1<d[to[e]]) {
        d[to[e]]=d[x]+1;
        q.push(to[e]);
      }
    }
  }
  return d[T]<=1000000;
}

int dfs(int x,int limit) {
  if (x==T || !limit) return limit;
  int tot=0;
  for (ri &i=cur[x];i<ed[x].size();i++) {
    int e=ed[x][i];
    if (d[to[e]]==d[x]+1 && w[e]) {
      int f=dfs(to[e],min(limit,w[e]));
      if (!f) continue;
      w[e]-=f; w[1^e]+=f;
      tot+=f; limit-=f;
      if (!limit) return tot;
    }
  }
  return tot;
}

int dinic() {
  int ret=0;
  while (bfs()) {
    memset(cur,0,sizeof(cur));
    ret+=dfs(0,INF);
  }
  return ret;
}

void init() {
    int tn=0,tm=0;
  for (ri i=1;i<=n;i++) {
    ++tn;
    for (ri j=1;j<=m;j++) {
        han[i][j]=tn;
        if (g[i][j]==‘#‘) tn++;
      }
    }
    for (ri i=1;i<=m;i++) {
      ++tm;
      for (ri j=1;j<=n;j++) {
        lie[j][i]=tm;
        if (g[j][i]==‘#‘) tm++;
      }
    }
    n=tn; m=tm;
    return;
}

void makegraph() {
  for (ri i=1;i<=n;i++) add_edge(0,i,1,0);
  for (ri i=1;i<=m;i++) add_edge(n+i,T,1,0);
  for (ri i=1;i<=tn;i++)
    for (ri j=1;j<=tm;j++) if (g[i][j]==‘*‘) add_edge(han[i][j],n+lie[i][j],1,0);
}

int main() {
  scanf("%d %d",&n,&m); tn=n; tm=m;
  for (ri i=1;i<=n;i++) scanf("%s",g[i]+1);
  init();
  makegraph();
  printf("%d\n",dinic());
}

原文地址:https://www.cnblogs.com/shxnb666/p/11104967.html

时间: 2024-10-09 04:15:45

luogu P2825 [HEOI2016/TJOI2016]游戏的相关文章

P2825 [HEOI2016/TJOI2016]游戏

题目描述 在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂.简单的说,这个游戏就是在一张地图上放上若干个炸弹,看是否能炸到对手,或者躲开对手的炸弹.在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到.炸弹能炸到的范围是该炸弹所在的一行和一列,炸弹的威力可以穿透软石头,但是不能穿透硬石头.给定一张n*m的网格地图:其中*代表空地,炸弹的威力可以穿透,可以在空地上放置一枚炸弹.x代表软石头,炸弹的威力可以穿透,不能在此放置炸

luogu P4091 [HEOI2016/TJOI2016]求和

传送门 这一类题都要考虑推式子 首先,原式为\[f(n)=\sum_{i=0}^{n}\sum_{j=0}^{i}S(i,j)*2^j*j!\] 可以看成\[f(n)=\sum_{j=0}^{n}2^j*j!\sum_{i=j}^{n}S(i,j)\] 又因为\[S(i,j)=\frac{1}{j!}\sum_{k=0}^{j}(-1)^k*\binom{j}{k}*(j-k)^i\] 所以\[f(n)=\sum_{j=0}^{n}2^j*j!\sum_{i=0}^{n}\frac{1}{j!}

【[HEOI2016/TJOI2016]游戏】

据说是网络流棋盘模型了 我们把每一个连续子段都看成一个点,我们先把所有的行上的连续子段找出来给他们编上号,所有列上的连续子段找出来也编上号 现在每个格子都有两个编号了,\(a[i][j]\)表示行所对应的连续子段的编号,\(b[i][j]\)表示列所对应的连续子段的编号 之后我们就需要把这些子段匹配起来就可以了,如果\(map[i][j]=='*'\),我们就从\(a[i][j]\)向\(b[i][j]\)连边,就可以表达出一个行连续子段只能和一个列连续子段匹配了 代码 #include<cst

Luogu P2824 [HEOI2016/TJOI2016]排序

Link 先二分答案,这样所有的数字就都变成了\(0,1\). 那么区间排序就相当于区间求和再区间覆盖了. #include<bits/stdc++.h> using namespace std; #define N 100007 int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;} int a[N],sum[N<&l

AC日记——#2057. 「TJOI / HEOI2016」游戏 LOJ

#2057. 「TJOI / HEOI2016」游戏 思路: 最大流: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define maxn 2000005 int n,m,s,t,que[maxn],deep[maxn],toth,totl,F[max

[Luogu 4092] HEOI/TJOI2016 树

[Luogu 4092] HEOI/TJOI2016 树 <题目链接> 搜了树剖标签不知道怎么就跳出了个暴搜题啊! 管他既然做了就发上来吧- 有修改标签就向下搜并修改,遇到标签即停止. 这题是真的真的短. #include <cstdio> #include <queue> using std::queue; const int MAXN=100010; bool flag[MAXN]; int n,q,cnt,head[MAXN],top[MAXN]; struct

[HEOI2016/TJOI2016]排序 解题报告

[HEOI2016/TJOI2016]排序 题意 给出一个大小为 \(n\) 的排列, 对这个排列进行 \(m\) 次操作, 操作分为以下两种, 0 l r 表示将区间 \([l,r]\) 的数升序排序. 1 l r 表示将区间 \([l,r]\) 的数降序排序. 询问 \(m\) 次操作后下标为 \(q\) 的数字. 思路 不看题解打死也想不出来系列 考虑二分答案. 设当前二分的答案为 \(mid\), 把原排列中 大于等于 \(mid\) 的数标记为 \(1\), 小于 \(mid\) 的数

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树)

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树) 题面 给出一个长度为\(n\)的字符串\(s\),以及\(m\)组询问.每个询问是一个四元组\((a,b,c,d)\),问\(s[a,b]\)的所有子串和字符串\(s[c,d]\)的最长公共前缀长度的最大值. \(n,m \leq 10^5\) 分析 显然答案有单调性.首先我们二分答案\(mid\),考虑如何判定. 如果mid这个答案可行,那么一定存在一个后缀x,它的开头在\([a,

bzoj4554【TJOI2016&amp;HEOI2016】游戏

4554: [Tjoi2016&Heoi2016]游戏 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 266  Solved: 167 [Submit][Status][Discuss] Description 在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂.简单的说,这个游戏就是在一张地图上放上若干个炸弹,看 是否能炸到对手,或者躲开对手的炸弹.在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张 地图上最多能放上多少个炸弹能