URAL 1519 Formula 1
2015-10-22 19:07
363 查看
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1519
陈丹琦的《基于连通性状态压缩的动态规划问题》的论文上的题目
题意:
给你m*n的棋盘,有的格子是障碍,问共有多少条回路使得经过每个非障碍格子恰好一次。
做法:
论文上的思路讲的很清楚了,这里用最小表示法来做。
因为(2 ≤ N, M ≤ 12),所以最多出现6个联通块,所以用8进制来做。
陈丹琦的《基于连通性状态压缩的动态规划问题》的论文上的题目
题意:
给你m*n的棋盘,有的格子是障碍,问共有多少条回路使得经过每个非障碍格子恰好一次。
做法:
论文上的思路讲的很清楚了,这里用最小表示法来做。
因为(2 ≤ N, M ≤ 12),所以最多出现6个联通块,所以用8进制来做。
#include <bits/stdc++.h> using namespace std; int N, M; #define maxn 15 #define HASH 30007 #define STATE 200010 int mp[maxn][maxn]; int pos[maxn]; int mark, ex, ey; int code[maxn]; struct HashMap { int head[HASH], next[STATE], cnt; long long state[STATE]; long long sum[STATE]; void init() { cnt = 0; memset(head, -1, sizeof(head)); } void push(long long sta, long long val) { int h = sta%HASH; for(int i = head[h]; i != -1; i = next[i]) { if(state[i] == sta) //如果这种状态已经存在 { sum[i] += val; return; } } state[cnt] = sta; sum[cnt] = val; next[cnt] = head[h]; head[h] = cnt++; } }hashmp[2];//滚动数组 void decode(int *code, long long sta) { for(int i = M; i >= 0; i--) { code[i] = sta&7; sta >>= 3; } } long long encode(int *code) //转化成2进制 { int cnt = 1; int vis[maxn]; memset(vis, -1, sizeof(vis)); vis[0] = 0; //0不连通 long long sta = 0; for(int i = 0; i <= M; i++) { if(vis[code[i]] == -1) vis[code[i]] = cnt++; code[i] = vis[code[i]]; sta <<= 3; sta |= code[i]; } return sta; } void AtLast(int *code) { for(int i = M; i > 0; i--) code[i] = code[i-1]; code[0] = 0; } void slove() { mark = 0; hashmp[mark].init(); hashmp[mark].push(0, 1); //开始时轮廓线在最上方 for(int i = 1; i <= N; i++) { for(int j = 1; j <= M; j++) { hashmp[mark^1].init();//初始化 if(mp[i][j] == 0) //不能放置 { for(int k = 0; k < hashmp[mark].cnt; k++) { decode(code, hashmp[mark].state[k]); code[j-1] = code[j] = 0; if(j == M) AtLast(code); hashmp[mark^1].push(encode(code),hashmp[mark].sum[k]); } } else //可以放置 { for(int k = 0; k < hashmp[mark].cnt; k++) { decode(code, hashmp[mark].state[k]); int left, up; left = code[j-1]; up = code[j]; if(left == 0 && up == 0) //情况1:没有上插头和左插头,新建一个联通分量 { if(mp[i+1][j] && mp[i][j+1]) { code[j-1] = code[j] = 13; //如果mp[i][j+1] = 1,则不可能出现j == M的情况 hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]); } } else if(left && up) //情况2:有上插头和左插头 { if(left != up) //上插头和左插头不联通,合并联通分量。 { code[j-1] = code[j] = 0; //则不可能再有右插头和下插头 for(int ii = 0; ii <= M; ii++) { if(code[ii] == up) code[ii] = left; } if(j == M) AtLast(code); hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]); } else if(left == up) //上插头和左插头联通 { if(i == ex && j == ey) //这种情况只可能出现在最后一个可以摆放的位置 { code[j-1] = code[j] = 0; if(j == M) AtLast(code); hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]); } } } else if((left&&(!up)) || (up&&(!left)))//情况3:上插头和左插头只存在一个 { int val; if(left) val = left; else val = up; if(mp[i][j+1]) //右边的格子可走 { code[j] = val; code[j-1] = 0; hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]); } if(mp[i+1][j]) //下面的格子可走 { code[j-1] = val; code[j] = 0; if(j == M) AtLast(code); hashmp[mark^1].push(encode(code), hashmp[mark].sum[k]); } } } } mark^=1; } } } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); while(~scanf("%d%d", &N, &M)) { memset(mp, 0, sizeof(mp)); bool flag = false; for(int i = 1; i <= N; i++) { char str[15]; scanf("%s", str); for(int j = 0; j < M; j++) { if(str[j] == '.') { mp[i][j+1] = 1; ex = i; ey = j+1; flag = true; } else if(str[j] == '*') mp[i][j+1] = 0; } } if(flag == false) //没有空块 { printf("0\n"); continue; } slove(); long long ans = 0;; for(int i = 0; i < hashmp[mark].cnt; i++) { ans += hashmp[mark].sum[i]; } printf("%lld\n", ans); } return 0; }
相关文章推荐
- usaco Computational Geometry 计算几何
- 动态加载js
- 换啤酒问题
- Codevs P3372 选学霸
- c# 把网络文件下载到本地
- 《一个程序员的奋斗史》
- sicily 1211. 商人的宣传
- C语言中运算符的结合性
- duilib 自定义控件1 CTileLayoutUI
- 中国万网
- Device Compatibility
- IOS 内存管理
- Java:Stackoverflow上人气最旺的10个Java问题
- 图像局部特征学习(笔记1之Canny边缘检测算子)
- 第四次作业——个人作业——软件案例分析
- Android基础入门教程——8.3.3 Paint API之—— MaskFilter(面具)
- php 字符串拆分成数组
- 解决VirtualBox分辨率太小及VBoxGuestAdditions_4.3.12.iso下载地址
- javascript 调用c++
- 二叉查找树