1. 程式人生 > 實用技巧 >USACO4.4 重疊的影象 Frame Up

USACO4.4 重疊的影象 Frame Up

題目連結

Solution

今天上午測試題...最後幾分鐘才看到要輸出所有解,於是爆成了 44pts...

根據輸入可以得到所有字母構成的矩形。如果字元 \(i\) 出現在了字元 \(j\) 的矩形上,那麼 \(i\) 的影象一定在 \(j\) 的影象上方,從 \(j\)\(i\) 連邊。

跑一個拓撲排序,每次可以選的是佇列裡所有點之一。因此需要 dfs 所有可能情況,最後存到變數裡按照字典序輸出。

手寫佇列要注意,不能直接對佇列排序,dfs 時會造成混亂。

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 2333;
char a[N][N];
int n, m, Num = 0, tot = 0, res = 0;
int vis[N], lx[N], rx[N], ly[N], ry[N], e[N][N];
int q[N], du[N], use[N];
string ans[2333333];

void dfs(int num, int stp)
{
    if(stp == Num)
    {
        res++;
        ans[res] = "";
        for(int i = 1; i <= stp; i++) ans[res] += (char)(use[i]);
        return ;
    }
    for(int i = 1; i <= num; i++)
    {
        int x = q[i], cnt = num - 1;
        for(int j = i; j < num; j++) q[j] = q[j + 1];
        for(int j = 'A'; j <= 'Z'; j++)
        {
            if(vis[j] && e[x][j])
            {
                du[j]--;
                if(du[j] == 0) q[++cnt] = j;
            }
        }
        use[stp + 1] = x;
        dfs(cnt, stp + 1);
        for(int j = num; j > i; j--) q[j] = q[j - 1];
        q[i] = x;
        for(int j = 'A'; j <= 'Z'; j++)
            if(vis[j] && e[x][j]) du[j]++;
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(e, 0, sizeof(e));
    memset(lx, 0x3f, sizeof(lx));
    memset(ly, 0x3f, sizeof(ly));
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
            if(a[i][j] >= 'A' && a[i][j] <= 'Z')
            {
                if(!vis[a[i][j]])
                {
                    vis[a[i][j]] = 1;
                    Num++;
                }
                lx[a[i][j]] = min(lx[a[i][j]], i);
                ly[a[i][j]] = min(ly[a[i][j]], j);
                rx[a[i][j]] = max(rx[a[i][j]], i);
                ry[a[i][j]] = max(ry[a[i][j]], j);
            }
        }
    for(int i = 'A'; i <= 'Z'; i++)
    {
        if(!vis[i]) continue;
        for(int j = ly[i]; j <= ry[i]; j++)
        {
            char ch1 = a[lx[i]][j], ch2 = a[rx[i]][j];
            if(vis[ch1] && ch1 != i) e[i][ch1] = 1;
            if(vis[ch2] && ch2 != i) e[i][ch2] = 1;
        }
        for(int j = lx[i]; j <= rx[i]; j++)
        {
            char ch1 = a[j][ly[i]], ch2 = a[j][ry[i]];
            if(vis[ch1] && ch1 != i) e[i][ch1] = 1;
            if(vis[ch2] && ch2 != i) e[i][ch2] = 1;
        }
    }
    memset(du, 0, sizeof(du));
    for(int i = 'A'; i <= 'Z'; i++)
    {
        if(!vis[i]) continue;
        for(int j = 'A'; j <= 'Z'; j++)
        {
            if(!vis[j]) continue;
            if(e[i][j] == 1) du[j]++;
        }
    }
    for(int i = 'A'; i <= 'Z'; i++)
    {
        if(!vis[i]) continue;
        if(du[i] == 0)
        {
            tot++;
            q[tot] = i;
        }
    }
    dfs(tot, 0);
    sort(ans + 1, ans + res + 1);
    for(int i = 1; i <= res; i++) cout << ans[i] << endl;
    return 0;
}