题解 P2741 【[USACO4.4]重叠的图像Frame Up】

· · 题解

这道题好难啊

对于我这个小蒟蒻来说

这道题,明显就是个拓扑 我觉得爆搜的都是巨佬

删除线用上瘾了

好,进入正题。这道拓扑题首先是要建边。因为他说每一条边都至少有一个。所以我们只要找出一个个矩阵的边界,这非常好找,然后开始建边。建边就是枚举每一个矩形,发现“有外员侵入”的就建一条边。比如

AAABBBA
A..B.BA
AAABBBA

此时,A矩阵的边界为上:1 下:3 左:1 右:7

B矩阵的边界同理懒 然后就枚举A矩阵,发现有B“侵入”,就A->b建一条边

边建好了,接下来就是拓扑。 由于他说不只一个情况,所以我们要去深搜。深搜就是把队列里面每一个入度为0的都拿出来跑一遍,而不是每次取头跑了。把每一次的答案记下来,sort一下就好了。

代码(你们最喜欢的)

#include<bits/stdc++.h>
using namespace std;
char a[31][31];
const int N=500001;
struct data{
    int x1=1e9,x2,y1=1e9,y2;
}x[27];
int node[N],head[N],nxt[N],into[N],zf,cnt,b[N],ans[N],bb[N],q[N],r,hh=1;
string ans2[N];
void add(int x,int y)
{
    node[++cnt]=y;
    nxt[cnt]=head[x];
    head[x]=cnt;
}
void dfs(int dep)
{
    if(dep>zf)
    {
        for(int i=zf;i>=1;i--){
            char c=ans[i]+'A'-1;
            ans2[hh]+=c;
        }
        hh++;
        return;
    }
    for(int i=1;i<=r;i++)
    {
        if(b[i]==0)
        {
            int rr=r;
            int x=q[i];
            for(int j=head[x];j;j=nxt[j])
            {
                into[node[j]]--;
                if(into[node[j]]==0)q[++r]=node[j];
            }
            b[i]=1;
            ans[dep]=x;
            dfs(dep+1);
            b[i]=0;
            for(int j=head[x];j;j=nxt[j])into[node[j]]++;
            r=rr;
        }

    }
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]!='.')
            {
                int h=(int)(a[i][j]-'A'+1);
                if(bb[h]==0)zf++;
                bb[h]=1;
                if(i<x[h].x1)x[h].x1=i;
                if(i>x[h].x2)x[h].x2=i;
                if(j<x[h].y1)x[h].y1=j;
                if(j>x[h].y2)x[h].y2=j;
            }
        }
    for(int i=1;i<=26;i++)
    {
        if(x[i].x1!=0){
            for(int j=x[i].x1;j<=x[i].x2;j++)
            {
                int h=a[j][x[i].y1]-'A'+1;
                if(h!=i)add(h,i),into[i]++;
                h=a[j][x[i].y2]-'A'+1;
                if(h!=i)add(h,i),into[i]++;
            }
            for(int j=x[i].y1;j<=x[i].y2;j++)
            {
                int h=a[x[i].x1][j]-'A'+1;
                if(h!=i)add(h,i),into[i]++;
                h=a[x[i].x2][j]-'A'+1;
                if(h!=i)add(h,i),into[i]++;
            }

        }
    }
    for(int i=1;i<=26;i++)
        if(bb[i]==1&&into[i]==0)q[++r]=i;
    dfs(1);
    sort(ans2+1,ans2+hh);
    for(int i=1;i<=hh-1;i++)
    {
        for(int j=0;j<zf;j++)printf("%c",ans2[i][j]);
        printf("\n");
    }
}

为什么我的码风上了这里就变得鬼畜了 好,没了

这是我的第一篇题解。
删除线太好用了