Gym 101482. I

来源:互联网 发布:linux服务器配置ipv6 编辑:程序博客网 时间:2024/06/05 10:58

题意:给一个n*n的邻接矩阵 代表 俩俩顶点之间的距离。一共n个点。然后问你。长度为w的回路是否存在,就是从u出发,最多每条边只能过一次最终回到u。(1nw1e15

思路:折半搜索,分为两块然后每一块枚举以后,爆搜。这样每一块的复杂度大概都是在7!的数量级,5e3左右。然后用一个set,dp[i]来存取以i作为路径终点的路径长度,搜完一块以后,第二块在第一块的答案中进行查找即可。
注意
“==”的优先级比“&”高!!!
“ x & (i << 1) == 0”的时候 一定要加括号!!!
“(x & (i << 1) )== 0”

#include <bits/stdc++.h>using namespace std;int n, vsSet[2];long long w, d[14][14];set<long long>dp[14];bool flag;void dfs(int cur, int sta, long long dist, int num, int type){    if(flag)    return ;    sta |= (1 << cur);    if(num == 0)    {        if(type == 0)   dp[cur].insert(dist);        else        {            for(int i = 1; i < n; i++)            {                if((vsSet[type] & (1 << i)) == 0)                {                    if(dp[i].find(w-dist-d[cur][i]) != dp[i].end())                    {                        flag = true;                        return ;                    }                }            }        }        return ;    }    for(int i = 0; i < n; i++)    {        if(sta & (1 << i))  continue;        if((vsSet[type] & (1 << i)) == 0) continue;        dfs(i, sta, dist+d[cur][i], num-1, type);    }}int main(){    scanf("%d%lld", &n, &w);    for(int i = 0; i < n; i++)    {        for(int j = 0; j < n; j++)        {            scanf("%lld", &d[i][j]);        }    }    if(n == 2)    {        if(d[0][1] + d[1][0] == w)  puts("possible");        else puts("impossible");    }    else    {        int uSet = (1 << n) - 2;//除了第一个顶点以外的全集。        for(int i = uSet - 1; i > 0; i = (i - 1) & uSet)//枚举子集        {            if(__builtin_popcount(i) != n / 2)  continue;            vsSet[0] = i;            vsSet[1] = uSet ^ i;            dfs(0,0,0,n/2,0);            dfs(0,0,0,n-1-n/2,1);            for(int j = 0; j < n; j++)  dp[j].clear();            if(flag)    break;        }        puts(flag ? "possible" : "impossible");    }    return 0;}
原创粉丝点击