UVA 1572 Self-Assembly(拓扑排序判断有向环)

题目连接:http://vjudge.net/problem/UVA-1572

题意:给定n种正方形,每种正方形的数量可视为无数个,正方形的每条边都有标号,正方形可进行旋转和翻转,对于两条边A+可与A-连接在一起,B+可与B-连接在一起,以此类推,00不能与任何边连接。问是否存在一种连接方式可使这些正方形无限拼接下去。

分析:我完全是看了题解才想明白的,自己写真的是一点想法都没有。题意可理解为是否存在一个正方形,以其为起点能够无限拼接下去,除了00外一共有52中标号,如果枚举n种正方形太浪费时间,所以需要简化模型。可以将正方形每条边作为一个节点,同一正方形上的点可以互相连通,若A+与B-在同一个正方形上,A+与A-拼接在一起后,则A-与B-视为连通,这样就确定了一条有向边B- —> A-,题目就变成所拼接的图中是否有有向环的问题了,当且仅当图中存在有向环时这些正方形可以无限拼接下去。可以用拓扑排序判断是否有有向环。在这里的编号是看的题解,觉得很值得学习。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 52;
int g[maxn][maxn], c[maxn];
int id(char a, char b)//给边标号
{
    int tmp = (a - 'A') * 2;
    tmp += b == '+' ? 0 : 1;
    return tmp;
}
void connect(char a1, char a2, char b1, char b2)//连接两条边
{
    if(a1 == '0' || b1 == '0') return;
    int u = id(a1, a2) ^ 1, v = id(b1, b2);
    g[u][v] = 1;
}
bool toposort(int u)
{
    c[u] = -1;
    for(int i = 0; i < maxn; i++)
    {
        if(g[u][i])
        {
            if(c[i] == -1) return true;
            if(!c[i] && toposort(i)) return true;
        }
    }
    c[u] = 1;
    return false;
}
bool solve()
{
    memset(c, 0, sizeof(c));
    for(int i = 0; i < maxn; i++)
        if(!c[i])
            if(toposort(i)) return true;//一旦存在有向环就可以无限循环下去
    return false;
}
int main()
{
    int t;
    char s[10];
    while(~scanf("%d",&t))
    {
        memset(g, 0, sizeof(g));
        while(t--)
        {
            scanf("%s",s);
            for(int i = 0; i < 4; i++)
            {
                for(int j = 0; j < 4; j++)
                {
                    if(i == j) continue;
                    connect(s[i*2], s[i*2+1], s[j*2], s[j*2+1]);//连接正方形的每两条边
                }
            }
        }
        if(solve()) printf("unbounded\n");
        else printf("bounded\n");

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值