TopCoder SRM 654 Div2 Problem 500 - OneEntrance (思维)

题意

小明有N个东西要搬进屋子。屋子是一颗树。
可是他在某个房间放下东西,就不能经过那个房间了。问现在有几种方法使他放下所有的东西。

思路

首先注意到N=9.
感觉这个范围超级无脑地乱搞。。。

一开始想胡乱DFS,想了一会儿没思路。

后来想DP,不会。

然后就想通过枚举所有序列,一一验证来统计答案。

枚举序列很简单,用next_permutation即可。

如何去验证?
一开始想用出度和入度来搞,可这是一个无向图,然后就跪了。

然后我就在脑子里模拟了一下。

假设一个序列是非法的,那么当我们搬进东西到某个屋子的时候,则搬到下一个屋子的路线是不通的。所以想办法一个接一个判断是否能从起点走到那个屋子即可。

所以可以先预处理出起点到所有点的路径。因为是树,所以不可能有第二条路。

对于每一个序列,如果路径里包括了之前某个走过的点,那么这个序列就是非法的!

暴暴暴暴暴暴暴力枚举检验即可。

代码

class OneEntrance {
public:
    vector<int> G[MAXN], permu;
    set<int> handle;
    int vis[MAXN], st;
    string mp[MAXN][MAXN];
    void DFS(int curNode, string path)
    {
        vis[curNode] = 1;
        for (int i = 0; i < SZ(G[curNode]); i++)
        {
            int v = G[curNode][i];
            if (vis[v]) continue;
            vis[v] = 1;
            mp[st][v] = path;
            DFS(v, path + (char)(v + '0'));
        }
    }

    bool Check()
    {
        MS(vis, 0);
        for (int i = 0; i < SZ(permu); i++)
        {
            string path = mp[st][permu[i]];
            for (auto j : path)
                if (vis[j - '0']) return false;
            vis[permu[i]] = 1;
        }
        return true;
    }

    int count(vector<int> a, vector<int> b, int s) {
        if (a.empty()) return 1;
        handle.clear(); permu.clear();
        MS(vis, 0);
        st = s;
        int sz = SZ(a);
        for (int i = 0; i < sz; i++) handle.insert(a[i]), handle.insert(b[i]);
        for (int i = 0; i < 10; i++) G[i].clear();
        for (int i = 0; i < sz; i++)
            G[a[i]].PB(b[i]), G[b[i]].PB(a[i]);
        DFS(s, "");
        for (auto i : handle)
            permu.PB(i);
        int ans = 0;
        do
        {
            if (permu.back() != st) continue;
            if (Check()) ans++;
        } while (next_permutation(permu.begin(), permu.end()));
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值