• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
镂空的行尸
   首页       联系   管理    订阅  订阅

Join The Future (剪枝 + 状态压缩)

一道暴力搜索的恶心剪枝题目。

先处理好某个点确定之后其他点的也确定的是谁,还有分别为什么情况,分别用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\n-1\n");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\n-1\n"); else{ printf("%lld\n",ans); for(int i = 1; i <= n; i ++) printf("%d%c", trodi[i], " \n"[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; }

 

more crazy more get!
posted @ 2018-10-13 15:38  镂空的行尸  阅读(190)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3