纪念一下这道题,写了一下午+一晚上,结果WA后才发现输出的不是拓扑排序。Exhausting....还是先做作业以后再补了……
过了两天,不管怎么说参考着一些别人的程序总算是写完了,大循环以位置为顺序一个个试人试下去,SCDP小循环以状态为顺序并考虑拓扑排序(这时候是以人的顺序来排位置的)实现状态转移。很长的一句话其实就是对于每个位置去试人并且每试一个人做一次全部的状态转移。贴个代码(YM zYc学长,看了他那个简洁完美的递推程序之后自己的程序写着写着就发现越来越接近他的程序了= =),虽然很想写解题报告但是还有作业要赶。。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
long long f[1 << 16];
int count(int i)
{
int j = 0;
while(i)
{
j += i & 1;
i >>= 1;
}
return j;
}
int main()
{
int n, m, seniority[16];
long long y;
long N, pre[16];
bool state[16];
scanf("%d%I64d%d", &n, &y, &m);
N = (1 << n) - 1;
y -= 2000;
memset(pre, 0, sizeof(pre));
while(m--)
{
int a, b;
scanf("%d%d", &a, &b);
pre[--b] |= 1 << --a;
}
memset(seniority, -1, sizeof(seniority));
memset(state, 0, sizeof(state));
for(int i = 0; i < n; i++)
for(seniority[i] = 0;; seniority[i]++)
{
if(seniority[i] >= n)
{
printf("The times have changed\n");
return 0;
}
if(state[seniority[i]])
continue;
memset(f, 0, sizeof(f));
f[0] = 1;
for(long j = 0; j <= N; j++)
if(f[j])
{
int c = count(j);
for(int k = 0; k < n; k++)
if(!(j & (1 << k)) && (seniority[k] == -1 || seniority[k] == c) && (pre[k] & j) == pre[k])
f[j | 1 << k] += f[j];
}
if(y > f[N])
{
y -= f[N];
continue;
}
else
{
state[seniority[i]] = 1;
break;
}
}
for(int i = 0; i < n; i++)
printf("%d%c", seniority[i] + 1, i == n - 1 ? '\n' : ' ');
return 0;
}