1 条题解

  • 0
    @ 2026-5-9 1:13:54

    简单费用流,5min 秒了。

    观察

    考虑循环格的性质,不难发现我们可以把每个格子看做一个节点,那么每个节点便都有一个出度指向其他节点。这个就很像内向基环树的性质啊,如果循环格合法(从每个点出发能回到自己),那么就得满足每个点都在一个环中。问题就转化为我们要最小化操作次数,使得所有点都在一个环里。

    继续考虑环的性质,显然形成环是需要每个点入度都是 11,出度也都是 11。出度的限制已经满足了,我们只要让每个点的入度都是 11 即可。这应该是一个很典的 trick 了吧。

    建模

    到这里就是好做的了。你发现把每个点拆成入点和出点,把每个节点能旋转到的四个方向分别看做容量为 11 的边,不用旋转的方向费用为 00,其余三个方向费用为 11,跑最小费用最大流即可。本质上就是个二分图匹配。

    时间复杂度为 EK 或者 Dinic 的复杂度。

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define eb(x) emplace_back(x)
    #define pb(x) push_back(x)
    #define lc(x) (tr[x].ls)
    #define rc(x) (tr[x].rs)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ldb;
    using pi=pair<int,int>;
    const int N=1005,M=1000005;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    int n,m,s,t;
    void getpos(int &x,int &y,int twd)
    {
        if(twd==0)x+=1;
        else if(twd==1)x-=1;
        else if(twd==2)y+=1;
        else if(twd==3)y-=1;
        if(x==0)x=n;
        else if(x==n+1)x=1;
        if(y==0)y=m;
        else if(y==m+1)y=1;
    }
    int getid(int x,int y,int tp)
    {
        return ((x-1)*m+y+tp*n*m);
    }
    int h[N],cur[N],idx=1;
    struct Edge{
        int v,ne;
        ll c,w;
    }e[M];
    void add(int u,int v,ll c,ll w)
    {
        e[++idx]={v,h[u],c,w};
        h[u]=idx;
    }
    void addeg(int u,int v,ll c,ll w)
    {
        add(u,v,c,w);
        add(v,u,0,-w);
    }
    ll dis[N],cost;
    bitset<N>vis;
    bool SPFA()
    {
        memset(dis,0x3f,sizeof(dis));
        vis.reset();
        queue<int>q;
        dis[s]=0;
        q.push(s);
        vis[s]=1;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=h[u];i;i=e[i].ne)
            {
                int v=e[i].v;ll c=e[i].c,w=e[i].w;
                if(dis[v]>dis[u]+w&&c)
                {
                    dis[v]=dis[u]+w;
                    if(vis[v]==0)
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return (dis[t]<=inf/2);
    }
    ll dfs(int u,ll mf)
    {
        if(u==t)return mf;
        ll sm=0;
        vis[u]=1;
        for(int i=cur[u];i;i=e[i].ne)
        {
            int v=e[i].v;ll c=e[i].c,w=e[i].w;
            if(vis[v]==0&&dis[v]==dis[u]+w&&c)
            {
                ll res=dfs(v,min(c,mf));
                cost+=w*res;
                e[i].c-=res;
                e[i^1].c+=res;
                mf-=res;
                sm+=res;
                if(mf==0)break;
            }
        }
        if(sm==0)dis[u]=inf;
        return sm;
    }
    void dinic()
    {
        ll flow=0;
        while(SPFA())
        {
            memcpy(cur,h,sizeof(h));
            vis.reset();
            flow+=dfs(s,inf);
        }
    }
    int main()
    {
        //freopen("sample.in","r",stdin);
        //freopen("sample.out","w",stdout);
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        cin>>n>>m;
        s=n*m*2+1,t=n*m*2+2;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                char c;
                cin>>c;
                for(int k=0;k<4;k++)
                {
                    int w=1,tx=i,ty=j;
                    getpos(tx,ty,k);
                    if(c=='D'&&k==0)w=0;
                    if(c=='U'&&k==1)w=0;
                    if(c=='R'&&k==2)w=0;
                    if(c=='L'&&k==3)w=0;  
                    addeg(getid(i,j,0),getid(tx,ty,1),1,w);              
                }
                addeg(s,getid(i,j,0),1,0);
                addeg(getid(i,j,1),t,1,0);
            }
        }
        dinic();
        cout<<cost;
        return 0;
    }
    
    • 1

    信息

    ID
    4836
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者