bzoj 1814 Ural 1519 Formula 1 插头DP

1814: Ural 1519 Formula 1

Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 942  Solved: 356
[Submit][Status][Discuss]

Description

Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well-known, that the city will conduct one of the Formula 1 events. Surely, for such an important thing a new race circuit should be built as well as hotels, restaurants, international airport - everything for Formula 1 fans, who will flood the city soon. But when all the hotels and a half of the restaurants were built, it appeared, that at the site for the future circuit a lot of gophers lived in their holes. Since we like animals very much, ecologists will never allow to build the race circuit over the holes. So now the mayor is sitting sadly in his office and looking at the map of the circuit with all the holes plotted on it. Problem Who will be smart enough to draw a plan of the circuit and keep the city from inevitable disgrace? Of course, only true professionals - battle-hardened programmers from the first team of local technical university!.. But our heroes were not looking for easy life and set much more difficult problem: "Certainly, our mayor will be glad, if we find how many ways of building the circuit are there!" - they said. It should be said, that the circuit in Vologda is going to be rather simple. It will be a rectangle N*M cells in size with a single circuit segment built through each cell. Each segment should be parallel to one of rectangle's sides, so only right-angled bends may be on the circuit. At the picture below two samples are given for N = M = 4 (gray squares mean gopher holes, and the bold black line means the race circuit). There are no other ways to build the circuit here. 一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数

Input

The first line contains the integer numbers N and M (2 ≤ N, M ≤ 12). Each of the next N lines contains M characters, which are the corresponding cells of the rectangle. Character "." (full stop) means a cell, where a segment of the race circuit should be built, and character "*" (asterisk) - a cell, where a gopher hole is located.

Output

You should output the desired number of ways. It is guaranteed, that it does not exceed 2^63-1.

Sample Input

4 4
**..
....
....
....



Sample Output


2

HINT

Source

 题解:什么叫做哈密顿回路,就是从一个点出发,经过所有点一次仅一次,

所有可以知道路不能交叉。

具体还是看cdqhttps://wenku.baidu.com/view/9cfbb16e011ca300a6c390d5.html

  1 #pragma GCC optimize(2)
  2 #pragma G++ optimize(2)
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<cstdio>
  7 #include<cstring>
  8 
  9 #define sz 200005
 10 #define ll long long
 11 using namespace std;
 12 
 13 int hs[sz],tot[2],sta[2][sz],bit[30];
 14 int n,m,c,ex,ey,mp[15][15];
 15 ll dp[2][sz],ans;
 16 char s[15];
 17 
 18 void add(int s,ll num)
 19 {
 20     int pos=s%sz;
 21     while (hs[pos]!=-1)
 22     {
 23         if (sta[c][hs[pos]]==s)
 24         {
 25             dp[c][hs[pos]]+=num;
 26             return;
 27         }
 28         pos++;
 29         if (pos==sz) pos=0;
 30     }
 31     dp[c][++tot[c]]=num;
 32     hs[pos]=tot[c];
 33     sta[c][tot[c]]=s;
 34 }
 35 void DP()
 36 {
 37     for (int i=1;i<=n;i++)
 38     {
 39         for (int k=1;k<=tot[c];k++)
 40             sta[c][k]<<=2;
 41         for (int j=1;j<=m;j++)
 42         {
 43             c^=1; tot[c]=0;
 44             memset(hs,-1,sizeof(hs));
 45             for (int k=1;k<=tot[c^1];k++)
 46             {
 47                 int s=sta[c^1][k];
 48                 ll num=dp[c^1][k];
 49                 int p=(s>>bit[j-1])&3,q=(s>>bit[j])&3;
 50                 if (!mp[i][j])
 51                 {
 52                     if (!p&&!q) add(s,num);
 53                 }
 54                 else if (!p&&!q)
 55                 {
 56                     if (!mp[i+1][j]||!mp[i][j+1]) continue;
 57                     s+=(1<<bit[j-1])+(1<<(bit[j]+1)) ;
 58                     add(s,num);
 59                 }
 60                 else if (!p&&q){
 61                     if (mp[i][j+1]) add(s,num);
 62                     if (mp[i+1][j]){
 63                         s+=(1<<bit[j-1])*q-(1<<bit[j])*q;
 64                         add(s,num);
 65                     }
 66                 }
 67                 else if (!q&&p){
 68                     if (mp[i+1][j]) add(s,num);
 69                     if (mp[i][j+1]){
 70                         s+=(1<<bit[j])*p-(1<<bit[j-1])*p;
 71                         add(s,num);
 72                     }
 73                 }
 74                 else if (p+q==2){
 75                     int b=1;
 76                     for (int t=j+1;t<=m;t++){
 77                         int v=(s>>bit[t])&3;
 78                         if (v==1) b++;
 79                         if (v==2) b--;
 80                         if (!b){
 81                             s-=(1<<bit[t]);
 82                             break;
 83                         }
 84                     }
 85                     s-=(1<<bit[j-1])+(1<<bit[j]);
 86                     add(s,num);
 87                 }
 88                 else if (p+q==4){
 89                     int b=1;
 90                     for (int t=j-2;t>=0;t--){
 91                         int v=(s>>bit[t])&3;
 92                         if (v==2) b++;
 93                         if (v==1) b--;
 94                         if (!b){
 95                             s+=(1<<bit[t]);
 96                             break;
 97                         }
 98                     }
 99                     s-=2*(1<<bit[j-1])+2*(1<<bit[j]);
100                     add(s,num);
101                 }
102                 else if (p==2&&q==1){
103                     s-=(1<<(bit[j-1]+1))+(1<<bit[j]);
104                     add(s,num);
105                 }
106                 else if (p==1&&q==2){
107                     if (i==ex&&j==ey) ans+=num;
108                 }
109             }
110         }
111     }
112 }
113 int main(){
114     for (int i=0;i<=25;i++)
115         bit[i]=i<<1;
116     scanf("%d%d",&n,&m);
117     tot[0]=1; dp[c][1]=1;
118     for (int i=1;i<=n;i++){
119         scanf("%s",s+1);
120         for (int j=1;j<=m;j++)
121             if (s[j]=='.') mp[i][j]=1,ex=i,ey=j;
122     }
123     DP();
124     printf("%lld\n",ans);
125 }

 

那么对于这道题目,分析其特殊性质。

 

转载于:https://www.cnblogs.com/fengzhiyuan/p/8486624.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 接下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (树形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问题就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用树形dp来解决这个问题,具体来说,我们可以将这个图看作是一棵树,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 树形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问题,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值