[SCOI2007] 蜥蜴

这道题主要难在网络流建模。
学了一早上的网络流然后找了个网络流题单练手然后发现这题正好在暑假集训的题单里。
那自然是得做的。
看到数据范围就知道可以网络流了。
求最少不可逃出可以转化为求最多可逃出,可以转化为最大流。
首先这题很明显有多个源点和汇点。
需要建一个超级源点和一个超级汇点。
接着考虑每一个点
如果这个点有石柱:

  1. 把它拆成一个入点和一个出点,首先将它的入点和出点相连,容量为 \(h_{i_j}\),因为这个石柱刚好可以跳走 \(h_{i_j}\) 个蜥蜴。
  2. 如果这个点上有蜥蜴,将它的入点与源点相连,容量是1。
  3. 如果这个点能跳出地图边界将它的出点与汇点相连,容量是INF。
  4. 接着把这个点和所有它可以跳到的点相连,容量为INF。

没有石柱的点一点用处都没有不用考虑。
然后跑网络流算法就可以了。
肯定是能过的这数据这么小/lh。
我写的 \(dinic\) 不过 \(EK\) 也能过。
代码如下:

点击查看代码
#include<bits/stdc++.h>
#define INF 1e9
#define R register
using namespace std;
struct edge{
    int v,f,re;
};
int n,m,e,s,t;
int pe[1205],pn[1205],dep[1205],cur[1205];
vector<edge>g[1205];
bool vis[1205];
inline void add(int u,int v,int w){
    R int szu=g[u].size(),szv=g[v].size();
    g[u].push_back({v,w,szv}),g[v].push_back({u,0,szu});
}
inline bool bfs(){
    queue<int>q;
    q.push(s),memset(dep,-1,sizeof(dep)),dep[s]=0,memset(cur,0,sizeof(cur));
    while(!q.empty()){
        R int x=q.front();q.pop();
        for(R int i=0;i<g[x].size();i++){
            edge k=g[x][i];
            if(k.f&&dep[k.v]==-1)dep[k.v]=dep[x]+1,q.push(k.v);
        }
    }
    return dep[t]!=-1;
}
inline int dfs(int x,int flow){
    if(x==t)return flow;
    for(R int i=cur[x];i<g[x].size();i++){
        cur[x]=i;
        R int v=g[x][i].v;
        if(dep[v]==dep[x]+1&&g[x][i].f){
            R int tf=dfs(v,min(flow,g[x][i].f));
            if(tf){g[x][i].f-=tf,g[v][g[x][i].re].f+=tf;return tf;}
            else dep[v]=-1;
        }
    }
    return 0;
}
inline int dinic(){
    R int res=0,ff;
    while(bfs())while(ff=dfs(s,INF))res+=ff;
    return res;
}
int mp[21][21],cnt,D,id[21][21],tot;
bool l[21][21];
inline int dis(int x,int y,int p,int q){return (x-p)*(x-p)+(y-q)*(y-q);}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m>>D,s=0,t=1001;
    for(R int i=1;i<=n;i++){
    	string s;
		cin>>s;
		for(R int j=0;j<m;j++)mp[i][j+1]=s[j]-'0';	
	}
	for(R int i=1;i<=n;i++){
    	string s;
		cin>>s;
		for(R int j=0;j<m;j++)l[i][j+1]=s[j]=='L';	
	}
	for(R int i=1;i<=n;i++)
		for(R int j=1;j<=m;j++)
			if(mp[i][j]){
				R int k1=(++cnt),k2=(++cnt);id[i][j]=cnt-1;
				add(k1,k2,mp[i][j]);
				if(l[i][j])add(s,k1,1),tot++;
				if(i<=D||j<=D||(n-i+1)<=D||(m-j+1)<=D)add(k2,t,INF);
			}
	for(R int i=1;i<=n;i++)
		for(R int j=1;j<=m;j++)
			for(R int x=1;x<=n;x++)
				for(R int y=1;y<=m;y++){
					if(i==x&&y==j)continue;
					if(dis(i,j,x,y)<=D*D&&mp[i][j]&&mp[x][y])add(id[i][j]+1,id[x][y],INF);
				}		
    cout<<tot-dinic();
}
posted @ 2025-08-27 16:21  zhuoheng  阅读(18)  评论(0)    收藏  举报