题意
小明有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;
}
};