[拓扑排序] PKU 2585 Window Pains

拓扑排序判断有向图是否有环,1A啊!!!

对每个位置(前3行前3列),如果它控制范围内的某个位置上为 j ,而这个位置原始值为 i ,则添加一条 i 到 j 的边,如果出现环则说明电脑出问题了;

不知道数据中是否含有非法的,所以就加了个判断:判断是否出现了非法状态,即某个位置出现了不属于这个位置的数字。

# include <cstdio>
# include <cstring>

# define N 5
# define NS ((N-1)*(N-1)) + 1

const int n = 3;
const int m = 9;
int in[NS];
int f[N][N];
char g[NS][NS];

void add(int i, int j)
{
    if (!g[j][i])
    {
        g[j][i] = 1;
        ++in[i];
    }
}

void build(void)
{
    memset(g, 0, sizeof(g));
    memset(in, 0, sizeof(in));
    int i, j, t, k;
    for (i = 1; i <= n; ++i)
    for (j = 1; j <= n; ++j)
    {
        k = j+(i-1)*n;
        if (f[i][j]     != k)    add(f[i][j]     ,k);
        if (f[i+1][j]   != k)    add(f[i+1][j]   ,k);
        if (f[i][j+1]   != k)    add(f[i][j+1]   ,k);
        if (f[i+1][j+1] != k)    add(f[i+1][j+1] ,k);
    }
}

int topsort(void)
{
    int cnt = 0;
    char vis[NS];
    memset(vis, 0, sizeof(vis));
    //for(int i = 1; i <= m; ++i)    printf("indegrees[%d] = %d\n", i, in[i]);
    while (cnt < m)
    {
        int c = 0;
        for (int i = 1; i <= m; ++i) if(!vis[i] && !in[i])
        {
            ++c;
            vis[i] = 1;
            for (int j = 1; j <= m; ++j) if (g[i][j])
                --in[j];
            break;
        }
        if (c == 0) return -1;
        ++cnt;
    }
    return 0;
}

bool check(void)
{
    if(f[1][1] != 1 && f[1][n+1] != 3 || f[n+1][1] != 7 || f[n+1][n+1] != 9)
    {
        return false;
    }
    if (f[1][2]!=1 && f[1][2]!=2) {return false;}
    if (f[2][1]!=1 && f[2][1]!=4) {return false;}
    if (f[1][3]!=2 && f[1][3]!=3) {return false;}
    if (f[3][1]!=4 && f[3][1]!=7) {return false;}
    if (f[2][2]!=1 && f[2][2]!=2 && f[2][2]!=4 && f[2][2]!=5) {return false;}
    if (f[2][3]!=2 && f[2][3]!=3 && f[2][3]!=5 && f[2][3]!=6) {return false;}
    if (f[3][2]!=7 && f[3][2]!=8 && f[3][2]!=4 && f[3][2]!=5) {return false;}
    if (f[3][3]!=9 && f[3][3]!=6 && f[3][3]!=5 && f[3][3]!=8) {return false;}
}

void solve()
{
    if (check() == false)
    {
        puts("THESE WINDOWS ARE BROKEN");
        return ;
    }
    int ans = topsort();
    if (ans == -1)
        puts("THESE WINDOWS ARE BROKEN");
    else
        puts("THESE WINDOWS ARE CLEAN");
}

int main()
{    
    char s[20];
    while (scanf("%s", s), strcmp(s, "ENDOFINPUT")!=0)
    {
        for (int i = 1; i <= n+1; ++i)
        for (int j = 1; j <= n+1; ++j)
            scanf("%d", &f[i][j]);
        build();
        solve();
        scanf("%s", s);
    }
    
    return 0;
}

直接DFS判断是否有环应该也可行。

原文地址:https://www.cnblogs.com/JMDWQ/p/2624875.html