[SCOI2007] 蜥蜴 题解

发现实际上就是在求有多少只蜥蜴能逃出来。

发现可以将柱子拆成入点和出点两部分,自己的出点向别人的入点连边,自己的入点向自己的出点连边。最后再加一个超级源点 \(S\),连接所有有蜥蜴的柱子入点;再加一个超级汇点 \(T\),连接所有能够跳出地图的柱子。

我们猛然发现:这个问题不就是求最大流吗?

考虑每种边的容量:

  1. \(S\) 到入点。由于每个柱子至多有一只蜥蜴,所以容量为 \(1\)

  2. 入点到出点。每个柱子只能向外跳 \(h_{i,j}\) 次,所以容量为 \(h_{i,j}\)

  3. 出点到入点/ \(T\):这个没有限制,随便跳多少个都行,所以容量无限。

时间复杂度看似是 \(O(n^8)\),但果真如此吗?

考虑 \(d\) 最大为 \(4\),距离 \(\le 4\) 的一共有 \(49\) 个,所以实际边数至多为 \(49n^2\)(而且根本不可能跑满)。

所以时间复杂度为 \(O(49n^6)\)

突然感觉用 \(FF\) 算法比 \(dinic\) 更优?

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=805,M=35005;
int n,m,de,s,t,id,h[N],d[N];
int k=1,to[M],w[M],nxt[M];
string st[N];int c[N],ans;
struct stone{int h,x,y;}a[N];
void add(int x,int y,int z){
	w[++k]=z;to[k]=y;
	nxt[k]=h[x];h[x]=k;
	w[++k]=0;to[k]=x;
	nxt[k]=h[y];h[y]=k;
}int bfs(){
    memset(c,-1,sizeof(c));
    queue<int>q;c[s]=0;
    q.push(s);d[s]=h[s];
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=h[x];i;i=nxt[i]){
            int y=to[i];int  lv=w[i];
            if(lv>0&&c[y]==-1){
                c[y]=c[x]+1;d[y]=h[y];
                q.push(y);if(y==t) return 1;
            }
        }
    }return 0;
}int dfs(int x,int ans){
    if(x==t) return ans;
    int sum=ans;
    for(int i=d[x];i&&sum;i=nxt[i]){
        d[x]=i;int y=to[i];int  lv=w[i];
        if(lv<1||c[y]!=c[x]+1) continue;
        int  zjy=dfs(y,min(sum,lv));
        sum-=zjy;w[i]-=zjy;w[i^1]+=zjy;
    }return ans-sum;
}int dinic(){
    int re=0;
    while(bfs())
        re+=dfs(s,1e9);
    return re;
}int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m>>de;
    for(int i=1;i<=n;i++){
        string t;cin>>t;t=" "+t;
        for(int j=1;j<=m;j++){
            if(t[j]=='0') continue;
            a[++id]={t[j]-'0',i,j};
        }
    }for(int i=1;i<=n;i++)
        cin>>st[i],st[i]=" "+st[i];
    s=id*2+1;t=id*2+2;
    for(int i=1;i<=id;i++){
        int ru=i*2-1,ch=i*2;
        double x=a[i].x,y=a[i].y;
        add(ru,ch,a[i].h);
        if(st[(int)x][(int)y]!='.')
            add(s,ru,1),ans++;
        if(x<=de||y<=de||x+de>n||y+de>m)
            add(ch,t,1e7);
        for(int j=1;j<=id;j++){
            if(i==j) continue;
            double z=a[j].x,w=a[j].y;
            if((x-z)*(x-z)+(y-w)*(y-w)<=de*de)
                add(ch,j*2-1,1e7);
        }
    }cout<<ans-dinic();
    return 0;
}
posted @ 2024-05-05 10:59  长安一片月_22  阅读(3)  评论(0编辑  收藏  举报