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

来源:互联网 发布:linux 重启服务器命令 编辑:程序博客网 时间:2024/05/12 09:22

题意

小明有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;    }};
0 0
原创粉丝点击