一道暴力搜索的恶心剪枝题目。
先处理好某个点确定之后其他点的也确定的是谁,还有分别为什么情况,分别用vis,sta来记录。当然可以直接使用一个3进制数来表示,但是这里需要额外写一个三进制数求值的函数较为麻烦。然后写完就是搜索的问题了,搜索方向就是给点为0,1一直下去,如果没有剪枝,时间复杂度应该是O(240),显然TLE,题意给出的限制很大,我们依据它来剪枝就好了。然后就是求最小的字典序,其实只需要传进最上面那个数据就可以了,因为你已经确定了01情况,剩下的就是选择每个数的最小或者次小的数。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 50; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; vector<pair<int, int> >cnst[maxn]; int T,n,m,aa,bb,cc; int l[maxn], r[maxn], trodi[maxn], vis[maxn]; LL b[maxn], odd[maxn][2], cnt[maxn][2], con[maxn], dans[maxn][2], ans; ///求字典序最小的 void update(LL vis, LL sta){ LL pre = 0; bool better = false; for(int i = 1; i <= n; i ++){ int now; if(vis & b[i]) now = l[i] + ((l[i] & 1) != ((sta >> i & 1) ^ pre)); else now = l[i]; if(better) trodi[i] = now; else{ if(now > trodi[i]) return ; if(now < trodi[i]) better = true, trodi[i] = now; } pre = pre ^ (now & 1); } } ///搜索所有01情况、剪枝、求总量 void dfs(int step, LL vis, LL sta){ if(step > n){ LL tmp = 0LL; for(int i = 0; i < 2; i ++){ if((vis&b[n]) && (sta >> n & 1) != i) continue; tmp = (tmp + dans[n][i]) % mod; } if(tmp){ update(vis, sta); ans = (ans + tmp) % mod; } return ; } dans[step][0] = dans[step][1] = 0;
///(0, 1) * (0, 1) 的四种结果,求出当前节点为0,1的个数 for(int i = 0; i < 2; i ++){ if((vis&b[step]) && (sta >> step & 1) != i) continue; for(int j = 0; j < 2; j ++){ if((vis&b[step - 1]) && (sta >>step - 1 & 1) != j) continue; dans[step][i] = (dans[step][i] + dans[step - 1][j] * cnt[step][i ^ j]% mod) % mod; } } if(cnst[step].empty()) dfs(step + 1, vis, sta); else for(int i =0; i < 2; i ++) if(dans[step][i]) dfs(step + 1, vis | con[step], sta | odd[step][i]); } void solve(){ ///求出某个点确定了之后其他的限制情况,当某点确定之后奇偶情况其他点为奇数的点 for(int i = 0; i <= n; i ++){ odd[i][0] = odd[i][1] = con[i] = 0; memset(vis, -1, sizeof(vis)); queue<int>que;while(!que.empty())que.pop(); vis[i] = 1;que.push(i); while(!que.empty()){ int u = que.front();que.pop(); con[i] |= b[u]; odd[i][vis[u]] |= b[u]; for(auto x : cnst[u]){ int v = x.first, w = x.second; if(~vis[v]){ if((vis[u] ^ vis[v] != w)){ printf("0 -1 ");return ; } }else{ vis[v] = vis[u] ^ w; que.push(v); } } } } memset(trodi, inf, sizeof(trodi)); ans = 0LL; dans[0][0] = 1; dfs(1, con[0], odd[0][0]); if(trodi[1] == inf) printf("0 -1 "); else{ printf("%lld ",ans); for(int i = 1; i <= n; i ++) printf("%d%c", trodi[i], " "[i == n]); } } int main(){ scanf("%d",&T); for(int i = 0; i < maxn; i ++) b[i] = 1ll << i; while(T --){ scanf("%d%d",&n,&m); for(int i = 1; i <= n; i ++){ scanf("%d%d", &l[i], &r[i]); cnt[i][l[i]&1] = (r[i] - l[i]) / 2 + 1; cnt[i][(l[i]&1)^1] = r[i] - l[i] + 1 - cnt[i][l[i]&1]; } for(int i = 0; i <= n; i ++) cnst[i].clear(); for(int i = 0; i < m; i ++){ scanf("%d%d%d",&aa, &bb, &cc); cnst[aa - 1].push_back(make_pair(bb, cc)); cnst[bb].push_back(make_pair(aa - 1, cc)); } solve(); } return 0; }