题意:构造一个点数不超过20无重边无自环的有向图,节点编号从0到n-1,使得从0到n-1的哈密顿路径数量恰好为k。
感觉完全没有思路。。不知道怎么构造。
去看了下别人的代码,原来可以做成1<-2<-…<-18一条路径,然后1-18都向编号比它大的节点连边。这样的话往回走就只有唯一的路径,所以假如说我当前在i,走到了j,j>i,那么就需要立刻从j到j-1直到i+1,然后再往后走。这样就相当于每个节点有选或不选两种状态,如果选的话就是从前面第一个比它小的选的节点跳过来,不选的话就是从i+1过来。所以如果有0->i,就相当于贡献了
218−i−1(1≤i<18)
(因为18是必选的,19不能回到18)。
既然不会做的话,那就乱搞一下吧~
假如说随便确定了一个图,怎么求路径数量呢?那就需要
O(220202)
的状压dp。不过我们可以先不求0->n-1的哈密顿路径数量,可以先求
i−>19,1≤i<19
,然后再连从0出去的边,这样的话就相当于是问是否存在一个子集和恰好为k。
我们知道
(189)
是一个非常大的数了,所以如果i->19的路径数量是在
k9
附近随机,那么就很容易一不小心就凑出个k来!所以我们可以二分边的总数,直到找到一个边的总数在那里随机
i−>19
的路径数量的平均值会离
k9
比较近,然后就在那里一直随机。
这样的话时间复杂度是
O(2nn2logn)≈109
的。所以dp的常数比较要用心卡一下才行。。。我一开始算错了时间复杂度以为是
O(2nnlogn)
的就没管,结果样例都过不去。。。
代码:
#include<bits/stdc++.h>
using namespace std;
const int n=20,N=20;
typedef long long LL;
class HamiltonianConstruction
{
public:
pair<int,int> edge[N*N];
int etot;
LL f[1<<N][N];
LL s[1<<N];
int prev[N];
int bit[1<<N];
inline void cal(int mid)
{
random_shuffle(edge,edge+etot);
memset(prev,0,sizeof(prev));
for(int i=mid;i--;)prev[edge[i].second-1]|=1<<edge[i].first-1;
memset(f,0,sizeof(f));
f[1<<n-2][n-2]=1;
for(int i=1;i<1<<n-1;++i)
for(int j=i,x;j;j^=1<<x)
if(f[i][x=bit[j&-j]])
for(int k=prev[x]&~i,y;k;k^=y)
{
y=k&-k;
f[i|y][bit[y]]+=f[i][x];
}
for(int i=n-2;i--;)s[1<<i]=f[(1<<n-1)-1][i];
for(int i=1;i<1<<n-2;++i)s[i]=s[i^i&-i]+s[i&-i];
}
inline vector<string> construct(int k)
{
for(int i=0;i<n;++i)bit[1<<i]=i;
for(int i=n-1;--i;)
for(int j=n;--j;)
if(i!=j)
edge[etot++]=make_pair(i,j);
vector<string> ans(N,string(N,'N'));
int l=0,r=100;
while(r-l>1)
{
int mid=l+r>>1;
cal(mid);
for(int i=1<<n-2;i--;)
if(s[i]==k)
{
for(int j=mid;j--;)ans[edge[j].first][edge[j].second]='Y';
for(int j=n-2;j--;)
if(i>>j&1)
ans[0][j+1]='Y';
return ans;
}
LL sum=0;
for(int i=n-2;i--;)sum+=s[1<<i];
if(sum>=k<<1)r=mid;
else l=mid;
}
for(;;)
{
cal(r);
for(int i=1<<n-2;i--;)
if(s[i]==k)
{
for(int j=r;j--;)ans[edge[j].first][edge[j].second]='Y';
for(int j=n-2;j--;)
if(i>>j&1)
ans[0][j+1]='Y';
return ans;
}
}
}
};
总结:
①构造的时候可以考虑一些特殊情况,或者根据题目中的特殊性质。比如说构造一个图,就可以先考虑一条链、完全图、树。
②如果没有构造的思路,不妨试试随机化!
③一定要算好时间复杂度!