找了一下网上好像没有题解,所以贴一篇。
链接:codeforces.com/gym/102012/problem/L
题意:
一个大小不超过6*6的网格图(一个nm的网格图,有n×m 个点,2n×m−n−m条边),每条边都可以没有。定义定向操作是给网格图的每一条边定一个方向,问有多少种不同的定向方法使定向后图中不存在有向环。
题解:轮廓线dp,状态是压缩一下轮廓线的传递闭包(2^49),有效状态峰值大概1W
代码:
#include <bits/stdc++.h>
using namespace std;
int T;
char h[20][200],l[20][200];
inline bool haveEdgeh(int i,int j) {
return h[i][j*2] == '-';
}
inline bool haveEdgel(int i,int j) {
return l[i][j*2-1] == '|';
}
int now,n,m;
map<long long,long long> f[2];
int uni[9][9],uni2[9][9];
inline void calc(int dir1,int dir2,int kp,long long val) {
if (dir2) {
if (dir2 == 1) {
if (uni[kp+1][kp] || uni[kp+1][kp-1]) {
return ;
}
}
else {
if (uni[kp][kp+1] || uni[kp-1][kp+1]) {
return ;
}
}
}
for (int i = 0;i <= m; i++)
for (int j = 0;j <= m; j++)
uni2[i][j] = uni[i][j];
for (int i = 0;i <= m; i++) {
uni2[kp-1][i] = uni2[i][kp-1] = uni2[kp][i] = uni2[i][kp] = 0;
}
if (dir2 == 1) {
int a[7],cnt = 0;
for (int i = 0;i <= m; i++)
if (i != kp && i != kp-1)
if (uni[i][kp] || uni[i][kp-1]) {
uni2[i][kp] = 1;
a[cnt++] = i;
}
for (int i = 0;i <= m; i++)
if (uni[kp+1][i] && i != kp && i != kp-1) {
uni2[kp][i] = 1;
for (int j = 0;j < cnt; j++)
uni2[a[j]][kp+1] = 1,uni2[a[j]][i] = 1;
}
}
else if (dir2 == -1) {
int a[7],cnt = 0;
for (int i = 0;i <= m; i++) {
if (i != kp && i != kp-1)
if (uni[kp][i] || uni[kp-1][i]) {
uni2[kp][i] = 1;
a[cnt++] = i;
}
}
for (int i = 0;i <= m; i++)
if (uni[i][kp+1] && i != kp && i != kp-1) {
uni2[i][kp] = 1;
for (int j = 0;j < cnt; j++)
uni2[kp+1][a[j]] = 1,uni2[i][a[j]] = 1;
}
}
if (dir1 == 1) {
for (int i = 0;i <= m; i++)
if (i != kp && i != kp-1)
if (uni[i][kp] || uni[i][kp-1]) {
uni2[i][kp-1] = 1;
}
}
else if (dir1 == -1) {
for (int i = 0;i <= m; i++) {
if (i != kp && i != kp-1)
if (uni[kp][i] || uni[kp-1][i]) {
uni2[kp-1][i] = 1;
}
}
}
if (dir1 == 1 && dir2 == -1) {
uni2[kp][kp-1] = 1;
for (int i = 0;i <= m; i++) {
if (i == kp || i == kp-1) {
continue;
}
if (uni2[i][kp])
uni2[i][kp-1] = 1;
}
}
if (dir2 == 1 && dir1 == -1) {
uni2[kp-1][kp] = 1;
for (int i = 0;i <= m; i++) {
if (i == kp || i == kp-1) {
continue;
}
if (uni2[kp][i])
uni2[kp-1][i] = 1;
}
}
long long rstatus = 0;
for (int i = m;i >= 0; i--) {
for (int j = m;j >= 0; j--) {
rstatus <<= 1;
if (uni2[i][j]) {
rstatus++;
}
}
}
f[now][rstatus] = f[now][rstatus] + val;
/* printf("%d %d %I64d %I64d\n",dir1,dir2,rstatus,val);
for (int i = 0;i <= m; i++) {
for (int j = 0;j <= m; j++) {
printf("%d ",uni2[i][j]);
}
printf("\n");
}*/
}
inline void dp(int posi,int posj,long long status,long long val) {
//printf("%I64d ",status);
for (int i = 0;i <= m; i++) {
for (int j = 0;j <= m; j++) {
if (status & 1) {
uni[i][j] = 1;
}
else
uni[i][j] = 0;
status >>= 1;
}
}
/* printf("%d %d %I64d\n",posi,posj,val);
for (int i = 0;i <= m; i++) {
for (int j = 0;j <= m; j++) {
printf("%d ",uni[i][j]);
}
printf("\n");
}*/
int len1,len2,set1[2],set2[2];
if (haveEdgel(posi,posj)) {
len1 = 2;
set1[0] = -1;
set1[1] = 1;
}
else {
len1 = 1;
set1[0] = 0;
}
if (haveEdgeh(posi,posj)) {
len2 = 2;
set2[0] = -1;
set2[1] = 1;
}
else {
len2 = 1;
set2[0] = 0;
}
for (int i = 0;i < len1; i++)
for (int j = 0;j < len2; j++) {
calc(set1[i],set2[j],posj,val);
}
}
inline long long reverse(long long status) {
long long rstatus = 0;
for (int i = 0;i <= m; i++) {
for (int j = 0;j <= m; j++) {
if (status & 1) {
uni[i][j] = 1;
}
else
uni[i][j] = 0;
status >>= 1;
}
}
for (int i = 1;i <= m; i++)
for (int j = 1;j <= m; j++) {
uni2[i][j] = uni[i-1][j-1];
}
for (int i = 0;i <= m; i++)
uni2[i][0] = uni2[0][i] = 0;
for (int i = m;i >= 0; i--) {
for (int j = m;j >= 0; j--) {
rstatus <<= 1;
if (uni2[i][j]) {
rstatus++;
}
}
}
return rstatus;
}
inline void work() {
memset(h,0,sizeof(h));
memset(l,0,sizeof(l));
f[1].clear();
f[0].clear();
scanf("%d%d\n",&n,&m);
for (int i = 1;i <= n; i++) {
int cnt = 1;
gets(h[i]+1);
if (i < n) {
gets(l[i]+1);
}
}
/*
for (int i = 1;i <= n; i++) {
printf("%s\n",h[i]+1);
if (i < n) {
printf("%s\n",l[i]+1);
}
}
*/
now = 0;
f[now][0] = 1;
map<long long,long long>::iterator it;
it = f[now].begin();
for (int i = 1;i <= n; i++) {
for (int j = 1;j <= m; j++) {
now ^= 1;
f[now].clear();
for (it = f[now^1].begin();it != f[now^1].end(); ++it) {
dp(i,j,it->first,it->second);
}
//cout << f[now].size() << endl;
}
now ^= 1;
f[now].clear();
for (it = f[now^1].begin();it != f[now^1].end(); ++it) {
long long newstatus = reverse(it->first);
f[now][newstatus] = /*f[now][newstatus] +*/ it->second;
}
}
//cout << f[now].size() << endl;
printf("%lld",f[now][0]);
}
int main() {
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d",&T);
while (T--) {
work();
if (T) {
printf("\n");
}
}
return 0;
}
/*
1
1
4 5
+-+-+-+ +
| | |
+ + +-+-+
| | |
+ + +-+-+
| | |
+-+-+-+-+
1
4 4
+-+-+-+
| | |
+ + + +
| | |
+ +-+-+
| | |
+-+-+-+
1
4 4
+-+-+-+
| | |
+ + + +
| | |
+ +-+-+
| | |
+-+-+-+
1
6 6
+-+-+-+-+-+
| | | | | |
+-+-+-+-+-+
| | | | | |
+-+-+-+-+-+
| | | | | |
+-+-+-+-+-+
| | | | | |
+-+-+-+-+-+
| | | | | |
+-+-+-+-+-+
+-+ +-+-+
| | |
+-+-+-+-+
3 3
+-+-+
| |
+-+-+
| |
+-+ +
*/