数位dp+有向图状压dp
数位dp:
枚举字典序,判断总情况数是否>=y
状压dp:
dp[i]代表座位集合i所有摆放情况数
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
typedef __int64 LL;
const int N=16;
vector<int> vv[N];
#define pb push_back
int getcount(int mask){
int cnt=0;
while(mask){
cnt++;
mask-=mask&-mask;
}
return cnt;
}
int check(int u,int mask){
for(int i=0;i<vv[u].size();i++){
int v=vv[u][i];
if(mask>>v&1)return 0;
}
return 1;
}
int vis[N];
int sta[N];
LL dp[1<<N];
int s[N];
int n,m;LL Y;
LL getdp(int id,LL num){
int ed=1<<n;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++){
s[i]=1<<i;
}
dp[0]=1;
for(int i=0;i<ed;i++){
for(int j=0;j<n;j++)if((i>>j&1)==0&&check(j,i)){
if(j>id){
dp[i|s[j]]+=dp[i];
if(dp[i|s[j]]>num)dp[i|s[j]]=num;
}
else if(getcount(i|s[j])==sta[j]+1){
dp[i|s[j]]+=dp[i];
if(dp[i|s[j]]>num)dp[i|s[j]]=num;
}
}
}
//for(int i=0;i<=id;i++)printf("%d ",sta[i]);printf(":%I64d\n",dp[ed-1]);
return dp[ed-1];
}
int dfs(int id,LL num){
if(id==n){
if(num==1)return 1;
else return 0;
}
for(int i=0;i<n;i++)if(!vis[i]){
sta[id]=i;
vis[i]=1;
LL tmp=getdp(id,num);
if(tmp>=num){
return dfs(id+1,num);
}
else {
num-=tmp;
}
vis[i]=0;
}
return 0;
}
int main(){
#ifdef DouBi
freopen("in.cpp","r",stdin);
#endif // DouBi
while(scanf("%d%I64d%d",&n,&Y,&m)!=EOF){
Y-=2000;
for(int i=0;i<n;i++)vv[i].clear();
for(int i=0;i<m;i++){
int a,b;scanf("%d%d",&a,&b);a--;b--;
vv[a].pb(b);
}
memset(vis,0,sizeof(vis));
if(dfs(0,Y)){
for(int i=0;i<n;i++){
printf("%d%c",sta[i]+1,i==n-1?'\n':' ');
}
}
else {
printf("The times have changed\n");
}
}
return 0;
}