码迷,mamicode.com
首页 > 其他好文 > 详细

fzu1977之插头DP

时间:2014-04-29 13:13:22      阅读:369      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   color   os   

mamicode.com,码迷 Problem 1977 Pandora adventure

Accept: 354    Submit: 1177
Time Limit: 1000 mSec    Memory Limit : 32768 KB

mamicode.com,码迷 Problem Description

The pollution of the earth is so serious that people can not survive any more. Fortunately, people have found a new planet that maybe has life, and we call it "Pandora Planet".

Leonardo Da Vinci is the only astronaut on the earth. He will be sent to the Pandora Planet to gather some plant specimens and go back. The plant specimen is important to the people to decide whether the planet is fit to live or not.

Assuming that Da Vinci can only move in an N×M grid. The positions of the plant specimens he wants to collect are all marked by the satellite. His task is to find a path to collect all the plant specimens and return to the spaceship. There are some savage beasts in the planet. Da Vinci can not investigate the grid with the savage beast. These grids are also marked by the satellite. In order to save time Da Vinci could only visit each grid exactly once and also return to the start grid, that is, you can not visit a grid twice except the start grid. You should note that you can choose any grid as the start grid.

Now he wants to know the number of different paths he can collect all the plant specimens. We only care about the path and ignore where the start grid is, so the two paths in Figure 1 are considered as the same.

mamicode.com,码迷
Figure 1

mamicode.com,码迷 Input

The first line of the input contains an integer T (T≤100), indicating the number of cases. Each case begins with a line containing two integers N and M (1≤N, M≤12), the size of the planet is N×M. Each of the following N lines contains M characters Gij(1≤i≤N, 1≤j≤M), Gij denotes the status of the grid in row i and column j, where ‘X‘ denotes the grid with savage beast, ‘*‘ denotes the safe grid that you can decide to go or not, ‘O‘ denotes the plant specimen you should collect. We guarantee that there are at least three plant specimens in the map.

mamicode.com,码迷 Output

For each test case, print a line containing the test case number (beginning with 1) and the number of different paths he can collect all the plant specimens. You can make sure that the answer will fit in a 64-bit signed integer.

mamicode.com,码迷 Sample Input

22 2OOO*4 4***OXO****O*XX**

mamicode.com,码迷 Sample Output

Case 1: 1Case 2: 7
题意:输入一个n*m的地图,其中字母‘O‘的点是必走点,字母‘X‘是不能走的点,字母‘*‘是可走可不走的点,求经过所有点‘O‘的不同回路路径个数(路线相同起始点不同视为相同路径)。

分析:由于需要求回路个数,所以能想到是插头DP,本题在最简单的求回路个数上增加一些必走的点和可走的点

对于可走的点只要在插头DP的时候如果p=q=0且该点可以不走,则就增加一种不走的状态:

if(!p && !q){
	if(mp[i][j] == ‘*‘)HashCalState(s,num);
	if(mp[i][j+1] == ‘X‘ || mp[i+1][j] == ‘X‘)continue; 
	s=s+(1<<bit[j-1])+2*(1<<bit[j]);
	HashCalState(s,num);
}

而问题在于如果求经过所有‘O‘的回路?

假设求经过所有可经过点的回路时碰到p=1,q=2合并连通块

则发生这种情况必须是最后一个可走的点,这样所有可走的点才会连通

在这里也是一样,只要记录最后一个必走的点‘O即可

在碰到p=1,q=2合并连通块的时候,这时候只需判断这个点是不是最后一个“O‘点并且可以连成环

判断连成环既已决策的点没有插头连着未决策的点,这样所有已决策的点连着必成环

if(p == 1 && q == 2){//成环 
	if(i == ex && j<ey)continue;
	if(i<ex)continue;
	s=s-(1<<bit[j-1])-2*(1<<bit[j]);//求解其他已决策的点十是否和未决策的点相连
	if(!s)sum+=num;
}

其他就是插头DP模版了

采用邻接表寻找状态时head数组可以开小点,head的大小和效率关系很大

另外本题好坑爹!!!用long long WA,用__int64 AC,平白无故查错一晚上+一中午

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef __int64 LL;
using namespace std;

const int MAX=30000+10;
const int maxn=50000+10;
const int N=12+10;
int n,m,index,size[2],bit[N];
int ex,ey;
int head[MAX],next[maxn];
LL dp[2][maxn],state[2][maxn],sum;
char mp[N][N];

void HashCalState(LL s,LL num){
	int pos=s%MAX;
	for(int i=head[pos];i != -1;i=next[i]){
		if(state[index][i] == s){
			dp[index][i]+=num;
			return;
		}
	}
	state[index][size[index]]=s;
	dp[index][size[index]]=num;
	//头插法
	next[size[index]]=head[pos];
	head[pos]=size[index]++;
}

void DP(){
	sum=0;
	index=0;
	size[index]=1;
	state[index][0]=0;
	dp[index][0]=1;
	for(int i=1;i<=n;++i){
		for(int k=0;k<size[index];++k)state[index][k]<<=2;
		for(int j=1;j<=m;++j){
			index=index^1;
			memset(head,-1,sizeof head);
			size[index]=0;
			for(int k=0;k<size[index^1];++k){
				LL s=state[index^1][k];
				LL num=dp[index^1][k];
				int p=(s>>bit[j-1])%4;
				int q=(s>>bit[j])%4;
				if(mp[i][j] == ‘X‘){//需要绕过 
					if(!p && !q)HashCalState(s,num);
				}else if(!p && !q){
					if(mp[i][j] == ‘*‘)HashCalState(s,num);
					if(mp[i][j+1] == ‘X‘ || mp[i+1][j] == ‘X‘)continue; 
					s=s+(1<<bit[j-1])+2*(1<<bit[j]);
					HashCalState(s,num);
				}else if(!p && q){
					if(mp[i][j+1] != ‘X‘)HashCalState(s,num);
					if(mp[i+1][j] != ‘X‘){
						s=s+q*(1<<bit[j-1])-q*(1<<bit[j]);
						HashCalState(s,num);
					}
				}else if(p && !q){
					if(mp[i+1][j] != ‘X‘)HashCalState(s,num);
					if(mp[i][j+1] != ‘X‘){
						s=s-p*(1<<bit[j-1])+p*(1<<bit[j]);
						HashCalState(s,num);
					}
				}else if(p == 1 && q == 1){
					int b=1;
					for(int t=j+1;t<=m;++t){
						int v=(s>>bit[t])%4;
						if(v == 1)++b;
						if(v == 2)--b;
						if(!b){
							s=s+(1<<bit[t])-2*(1<<bit[t]);
							break;
						}
					}
					s=s-(1<<bit[j-1])-(1<<bit[j]);
					HashCalState(s,num);
				}else if(p == 2 && q == 2){
					int b=1;
					for(int t=j-2;t>=0;--t){
						int v=(s>>bit[t])%4;
						if(v == 2)++b;
						if(v == 1)--b;
						if(!b){
							s=s-(1<<bit[t])+2*(1<<bit[t]);
							break;
						}
					}
					s=s-2*(1<<bit[j-1])-2*(1<<bit[j]);
					HashCalState(s,num);
				}else if(p == 1 && q == 2){//成环 
					if(i == ex && j<ey)continue;
					if(i<ex)continue;
					s=s-(1<<bit[j-1])-2*(1<<bit[j]);
					if(!s)sum+=num;
				}else if(p == 2 && q == 1){
					s=s-2*(1<<bit[j-1])-(1<<bit[j]);
					HashCalState(s,num);
				}
			}
		}
	}
}

int main(){
	for(int i=0;i<N;++i)bit[i]=i<<1;
	int t,num=0;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i)scanf("%s",mp[i]+1);
		ex=ey=-1;
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j)if(mp[i][j] == ‘O‘)ex=i,ey=j;
			mp[i][m+1]=‘X‘;
		}
		for(int j=1;j<=m;++j)mp[n+1][j]=‘X‘;
		DP();
		if(ex == -1)++sum;
		printf("Case %d: %I64d\n",++num,sum);
	}
	return 0;
}
/*
100
12 12
************
************ 
************ 
************ 
************ 
************ 
************ 
************ 
************ 
************ 
************ 
************ 
*/ 

fzu1977之插头DP,码迷,mamicode.com

fzu1977之插头DP

标签:des   style   blog   http   color   os   

原文地址:http://blog.csdn.net/xingyeyongheng/article/details/24652559

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!