题目大意:有不超过14个点组成的完全图,给出邻接矩阵,问是否存在长度为W的欧拉回路?
数据范围:n<=14, w<=1e15;
standard input/output 7 s, 256 MB
分析:直接暴力是14!的复杂度,显然不能通过;
考虑折半搜索,我们取0号点为起点,然后把所有的点分成两半;
两边分别暴力跑,最后检查一边,看另一边是否有可行的路径即可;
复杂度为C(N,N/2)*(n/2)!;
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <climits> #include <cstring> #include <string> #include <set> #include <bitset> #include <map> #include <queue> #include <stack> #include <vector> #include <cassert> #include <ctime> #define rep(i,m,n) for(i=m;i<=(int)n;i++) #define inf 0x3f3f3f3f #define mod 1000000007 #define vi vector<int> #define pb push_back #define mp make_pair #define fi first #define se second #define ll long long #define pi acos(-1.0) #define pii pair<int,int> #define sys system("pause") #define ls (rt<<1) #define rs (rt<<1|1) #define all(x) x.begin(),x.end() const int maxn=1e5+10; const int N=4e5+10; using namespace std; ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);} ll qmul(ll p,ll q,ll mo){ll f=0;while(q){if(q&1)f=(f+p)%mo;p=(p+p)%mo;q>>=1;}return f;} ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;} int n,m,k,t,c[2]; ll w,d[14][14]; set<ll>dp[14]; bool flag; void dfs(int pos,int sta,ll now,int lim,int tp) { if(flag)return; int i; sta|=(1<<pos); if(lim==0) { if(tp==1) { rep(i,1,n-1) { if(c[tp]>>i&1)continue; if(dp[i].find(w-now-d[i][pos])!=dp[i].end()) { flag=true; return; } } } else dp[pos].insert(now); return; } rep(i,0,n-1) { if((sta>>i&1)||(c[tp]>>i&1)==0)continue; dfs(i,sta,now+d[pos][i],lim-1,tp); } } int main(){ int i,j; scanf("%d%lld",&n,&w); rep(i,0,n-1)rep(j,0,n-1)scanf("%lld",&d[i][j]); if(n==2) { if(d[0][1]+d[1][0]==w)puts("possible"); else puts("impossible"); } else { int all=((1<<n)-2); for(i=all-1;i;i=((i-1)&all)) { if(__builtin_popcount(i)!=n/2)continue; c[0]=c[1]=0; rep(j,1,n-1) { if(i>>j&1)c[0]|=(1<<j); else c[1]|=(1<<j); } dfs(0,0,0,n/2,0); dfs(0,0,0,n-1-n/2,1); rep(j,0,n-1)dp[j].clear(); if(flag)break; } puts(flag?"possible":"impossible"); } return 0; }
时间: 2024-11-09 17:40:34