【基於聯通性的狀態壓縮動態規劃】

  


      以前一直被【jyltxdztysdtgh】嚇到,雖然cdq的論文看的懂,但一直沒有寫,太噁心了。

      不過這個時候是必須要寫了。

      先貼幾個鏈接:

       http://www.notonlysuccess.com/index.php/plug_dp/

      http://blog.csdn.net/jasonzhu8/article/details/5779518


      就小小的總結一下,寫【......】的時候讓人感覺實在玩接水管遊戲,其實只要把各種狀態寫在紙上,細心一點,多寫幾遍之後就沒那麼噁心了。

       利用4進制,0表示無括號,1表示左括號,2表示右括號,爲了防止寫錯,就寫了兩個過程,get(state, p)和cor(state,p,alt),分別是詢問state的第p位 / 把state的第p位染成alt,這樣每次轉移時只用這兩個過程,就是的對於一遇到很多運算套在一起就暈(比如我)是一個很大的幫助,雖然會增加代碼量,但是爲了寫對還是值得的。

     

      主要就是要注意細節,換行時的轉移,障礙的轉移,hash表的處理,只要細節處理好了,就基本上差不多了。

      雖然不好調,但是模塊化應該還是沒有問題的。


       ural1519:

     模板題,曼哈頓迴路個數。

# include <cstdlib>
# include <cstdio>
# include <cmath>
# include <cstring>
# include <ctime>

using namespace std;

const int S = 15000;

typedef long long int64;
struct HashMap
{
	int top, linke[S*10], next[S*10], point[S*10];
	int link(int x, int y)
	{
		++top; next[top] = linke[x]; linke[x] = top; point[top] = y;
		return top;
	}
	int ask(int state)
	{
		int ke, hs = state % 10009; 
		for (ke = linke[hs]; ke; ke = next[ke])
		   if (point[ke] == state) break;
	    return ke? ke: link(hs, state);
	}
}hash;

int n, m, head[2], tail[2], que[2][S*10], p;
int64 ans, f[2][S*10];
int mat[30], bct[30];
int lastn, lastm;
char c[30][30];
bool step[S*10];
inline int get(int state, int pl)
{
	return (state>>((pl-1)<<1))&3;
}
inline void cor(int &state, int p, int alt)
{
	int pri = get(state, p);
	state ^= pri << ((p-1)<<1);
	state |= alt << ((p-1)<<1);
}
void update(int SX, int x, int y)
{
     f[p][x] += f[!p][y];
     if (!step[x]) que[p][++tail[p]] = SX,step[x]=true;
}
void expand(int state, int line, int list)
{
	 //printf("%d\n", state);
	 int i,aim, X, Y, Z, pX, pY;
	 pX = list+1; pY = list+2;
     X = get(state, pX); Y = get(state, pY);
     if (c[line][list]=='*'&&(X!=0||get(state,list)!=0)) return;
     if (list == m)
     {
		if (!X) update(state<<2, hash.ask(state<<2),hash.ask(state));
	 }
	 else if (c[line][list+1] == '*')
	 {	
		if ((!X)&&(!Y))
		  update(state, hash.ask(state),hash.ask(state));	
	 } 
	 else if ((!X) && (!Y))
	 {
		aim = state; cor(aim, pX, 1); 
		cor(aim, pY, 2);
	    update(aim, hash.ask(aim),hash.ask(state));
	 } 
	 else if ((!X)||(!Y))
	 {
		update(state, hash.ask(state), hash.ask(state));
		aim = state; cor(aim, pX, 0); 
		cor(aim, pY, 0); 
		cor(aim, pX, Y); 
		cor(aim, pY, X);
		update(aim, hash.ask(aim),hash.ask(state));
	 }
	 else if (X==2 && Y==1)
	 {
	    aim = state; cor(aim, pX, 0); 
		cor(aim, pY, 0);
	    update(aim, hash.ask(aim),hash.ask(state));
	 }
	 else if (X==Y)
	 {
		memset(mat,0,sizeof(mat));
		memset(bct,0,sizeof(bct));	
		for (i = 1; i <= m+1; i++)
		{
			Z = get(state, i);
			if (Z==1) mat[++mat[0]] = i;
			else if (Z==2) bct[i] = mat[mat[0]], bct[mat[mat[0]--]] = i;
		}
		aim = state; cor(aim, pX, 0); cor(aim, pY, 0);
		if (X==1) cor(aim, bct[pY], 1), update(aim, hash.ask(aim),hash.ask(state));
		if (X==2) cor(aim, bct[pX], 2), update(aim, hash.ask(aim),hash.ask(state));	
	 }
	 else if (lastn == line && lastm-1 == list)
	 {
		aim = state; cor(aim, pX, 0); cor(aim, pY, 0);
	    if (!aim)ans += f[!p][hash.ask(state)];
	 }
}
void work()
{
	int i, j;
	que[1][head[1] = tail[1] = 1] = 0; p = 1; 
	f[1][hash.ask(0)] = 1;
	for (i = 1; i <= n; i++)
	  for (j = 0; j <= m; j++)
	  {
			p ^= 1; 
			memset(f[p], 0, sizeof(f[p])); head[p] = 1; tail[p] = 0;
			memset(step, false, sizeof(step));
			for (;head[!p] <= tail[!p]; head[!p]++)
			   expand(que[!p][head[!p]], i, j);
			if (i == lastn && j == lastm) return;
	  }
}
int main()
{
	int i, j;
	freopen("ural1519.in", "r", stdin);
	freopen("ural1519.out", "w", stdout);
	scanf("%d%d\n", &n, &m);
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= m; j++)
		{
		  scanf("%c", &c[i][j]);
		  if (c[i][j] == '.') lastn = i, lastm = j;
		}
		scanf("\n");
	}
	work();
	//printf("%d\n", hash.top);
	printf("%I64d", ans);
	return 0;
}

poj1379:

有限制的曼哈頓路徑數量。

僅僅只是對上面的程序改了一點點。      


# include <cstdlib>
# include <cstdio>
# include <cmath>
# include <cstring>
# include <ctime>

using namespace std;

const int S = 1000;
typedef long long int64;

int linke[S], next[S], point[S];
int bct[20], que[2][S], head[2], tail[2], mat[20];
int64 ans, f[2][S];
int n, m, lastn, lastm, X, Y, pX, pY, p;
bool step[S];
char c[20][20];
int top;

inline int link(int x, int y)
{
	++top; next[top] = linke[x]; linke[x] = top; point[top] = y;
	return top; 
}
inline int ask(int state)
{
	int ke , hs = state % 997;
	for (ke = linke[hs]; ke; ke = next[ke])
	  if (point[ke] == state) break;
	return ke? ke:link(hs, state);
}
inline int get(int state, int pl)
{
	return (state>>((pl-1)<<1))&3;
}
inline void cor(int &state, int p, int alt)
{
	int tp = get(state, p);
	state ^= tp  << ((p-1)<<1);
	state ^= alt << ((p-1)<<1);
}
inline void update(int state, int x, int y)
{
	f[p][x] += f[!p][y];
	if (!step[x]) que[p][++tail[p]] = state, step[x] = true;
} 
void expand(int state, int line , int list)
{
    int aim, i, pX = list+1, pY = list+2, X = get(state, pX), Y = get(state, pY);
    if (list == m)
    {
		if (!X) update(state<<2, ask(state<<2), ask(state));
	}
	else if (c[line][list+1] == '#')
	{
		if ((!X)&&(!Y)) update(state, ask(state), ask(state));
	}
	else if ((!X)&&(!Y)) 
	{
		aim = state; cor(aim, pX, 1); cor(aim, pY, 2);
		update(aim, ask(aim), ask(state));
	}
	else if ((!X)||(!Y))
	{
		aim = state; update(aim, ask(aim), ask(state));
		cor(aim, pX, 0); cor(aim, pY, 0);
		cor(aim, pX, Y); cor(aim, pY, X);
		update(aim, ask(aim), ask(state));
	}
	else if (X==2&&Y==1)
	{
		aim = state; 
		cor (aim, pX, 0); cor(aim, pY, 0);
		update(aim, ask(aim), ask(state));
	}
	else if (X==Y)
	{
		aim = state; memset(bct,0,sizeof(bct)); memset(mat,0,sizeof(mat));
		for (i = 1; i <= m+1; i++)
        {
			int z = get(state, i);
			if (z == 1) mat[++mat[0]] = i;
			else if (z== 2) bct[i] = mat[mat[0]], bct[mat[mat[0]--]] = i;
		}
		cor(aim, pX, 0); cor(aim, pY, 0);
		if (X==1) cor(aim, bct[pY], 1), update(aim, ask(aim), ask(state));
		if (X==2) cor(aim, bct[pX], 2), update(aim, ask(aim), ask(state));
	}
	else if (line == lastn && list == lastm-1)
	{
		aim = state; cor(aim, pX, 0); cor(aim, pY, 0);
		if (!aim) ans += f[!p][ask(state)];
	}
}

void origin()
{
	memset(c, sizeof(c), 0);
	memset(linke, 0, sizeof(linke));
	memset(point, 0, sizeof(point));
	memset(next,  0, sizeof(next));
	top = 0; ans =0; memset(f, 0, sizeof(f));
}

void work()
{
	int i, j;
	int aim = 0; cor(aim, 2, 1); cor(aim, m+1, 2);
	p = 1; que[p][head[1]=tail[1]=1] = aim; f[p][ask(aim)] = 1;
	for (i = 1; i <= n; i++)
	  for (j = 0; j <= m; j++)
	   {
	      if (i == lastn&& j == lastm) return;
		  p^=1;
		  memset(f[p], 0, sizeof(f[p]));
		  memset(step, 0, sizeof(step));
		  head[p] = 1;tail[p] = 0;
		  for (;head[!p]<=tail[!p];head[!p]++)
		    expand(que[!p][head[!p]], i, j);
	   }
}
int main()
{
	int i, j;
	//freopen("1739.in", "r", stdin);
	//freopen("1739.out", "w", stdout);
	for (;;)
	{
	  origin();
	  scanf("%d%d\n", &n, &m);
	  if ((!n)&&(!m)) return 0;
	  for (i = n; i >= 1; i--)
      {
		  for (j = 1; j <= m; j++)
		    scanf("%c", &c[i][j]);
		  scanf("\n");
	  }
	  for (i = 1; i <= n; i++)
	      for (j = 1; j <= m; j++)
	        if (c[i][j]=='.') lastn = i, lastm = j;
	  work();
	 // printf("%d\n", top);
	  if (c[1][1] == '#' || c[1][m] == '#') printf("0\n");
	  else printf("%I64d\n", ans);
	}
	return 0;
}


  zoj3256

上題 + 矩乘

每次先用按格轉移的方式預處理出行與行之間的轉移,然後用矩乘優化。

寫的很醜很醜。。。。。。在zoj上tle了。。。。。。

# include <cstdlib>
# include <cstdio>
# include <cmath>
# include <cstring>
# include <ctime>

using namespace std;

typedef long long int64;

const int mo = 7777777, S = 580;
int tot, n, m, p;
int bct[30], mat[30], head[2], tail[2], que[2][S+10];
int top, next[S+10], linke[S+10], point[S+10]; 
int64 f[2][S*5], g[180][180], mtx[180][180], tmp[180][180];
bool step[S*5];

inline int get(int state, int p)
{
	return (state>>((p-1)<<1))&3;
}
inline void cor(int &state, int p, int alt)
{
	int pri = get(state, p);
	state ^= pri<<((p-1)<<1);
	state |= alt<<((p-1)<<1);
}
inline int link(int x, int y)
{
	++top; next[top] = linke[x]; linke[x] = top; point[top] = y;
	//if (top > 200) exit(0);
	return top;
}
inline int ask(int state)
{
	int ke,hs = state % 173;
	for (ke = linke[hs]; ke ; ke = next[ke])
	  if (point[ke] == state) break;
	return ke?ke:link(hs, state);
}
inline bool check(int state)
{
	int i, bt = 0, Z;
	for (i = 1; i <= n; i++)
	{
		Z = get(state, i);
		if (Z == 1) bt++;
		else if (Z == 2) bt--;
		if (bt<0) return false;
	}
	return bt?false:true; 
}
inline void update(int st, int x, int y)
{
	int Dx = ask(x);int Dy = ask(y);
	f[p][Dx] += f[!p][Dy];
	if (step[Dx]!=st) step[Dx] = st, que[p][++tail[p]] = x; 
}
void expand(int st, int state, int list)
{
	int i, aim, pX = list+1, pY = list+2, X = get(state, pX), Y = get(state, pY);
	
	if (list == n-1 && X == 1 && Y == 2)
	{
		aim = state; cor(aim, pX, 0); cor(aim, pY, 0);
		if (!aim) update(st, aim, state);
	}
	else if ((!X)&&(!Y))
	{
		aim = state; cor(aim, pX, 1); cor(aim, pY, 2);
		update(st, aim, state);
	}
	else if ((!X)||(!Y))
	{
		aim = state; update(st, aim, state);
		cor(aim, pX, Y); cor(aim, pY, X);
		update(st, aim, state);
	}
	else if (X == 2&& Y == 1)
	{
		aim = state;
		cor(aim, pX, 0); cor(aim, pY, 0);
		update(st, aim, state);
	}
	else if (X == Y)
	{
		aim = state; cor(aim, pX, 0); cor(aim, pY, 0);
		memset(bct, 0, sizeof(bct)); memset(mat, 0, sizeof(mat));
		for (i = 1; i <= n+1; i++)
		{
			int Z = get(state, i);
			if (Z == 1) mat[++mat[0]] = i;
			else if (Z == 2) bct[i] = mat[mat[0]], bct[mat[mat[0]--]] = i;
		}
		if (X == 1) cor(aim, bct[pY], 1), update(st, aim, state);
		if (X == 2) cor(aim, bct[pX], 2), update(st, aim, state);
	}
}
void work(int state)
{
    int i;
	p = 1;head[p] = tail[p] = 1; que[1][1] = state;  
	memset(f, 0, sizeof(f)); f[p][ask(state)] = 1;
    for (i = 0; i <  n; i++)
    {
		p ^= 1; head[p] = 1; tail[p] = 0;
		memset(f[p], 0, sizeof(f[p]));
		memset(step, false, sizeof(step));
		for (;head[!p]<= tail[!p];head[!p]++)
		  if (que[!p][head[!p]]!=0) expand(state,que[!p][head[!p]], i);
	}
	for (;head[p] <= tail[p];head[p]++)
	   if (get(que[p][head[p]], n+1)==0)
	     mtx[ask(state)][ask(que[p][head[p]]<<2)] += f[p][ask(que[p][head[p]])];
}
void dfs(int p, int state)
{
	if (p == 0) {if (check(state)&&(state!=0)) work(state<<2)/*, printf("%d\n", state)*/;	return;}
	dfs(p-1,  state<<2);
	dfs(p-1, (state<<2)+1);
	dfs(p-1, (state<<2)+2);
}
void dfsp(int p, int state)
{
	if (p == 0) 
	{
		 if (check(state)) 
		  ask(state<<2);
		return;
	};
	dfsp(p-1,  state<<2);
	dfsp(p-1, (state<<2)+1);
	dfsp(p-1, (state<<2)+2);
}
void mul(int64 c[180][180], int64 a[180][180], int64 b[180][180])
{
	int i, j, k;
	memset(tmp, 0, sizeof(tmp));
	for (i = 1; i <= tot; i++)
	  for (j = 1; j <= tot; j++)
	    for (k = 1; k <= tot; k++)
	      tmp[i][j] = (tmp[i][j] + a[i][k]*b[k][j]) % mo;
	for (i = 1; i <= tot; i++)
	  for (j = 1; j <= tot; j++)
	      c[i][j] = tmp[i][j]; 
}
void origin()
{
	top = 0; memset(next, 0, sizeof(next));
	memset(linke, 0, sizeof(linke));
	memset(point, 0, sizeof(point));
	memset(g, 0, sizeof(g));
	memset(mtx, 0, sizeof(mtx));
}
int main()
{
	int i, j;
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	while (scanf("%d%d", &n, &m)!=EOF)
	{ 
	  origin();
	  dfsp(n,0);
	  tot = top;
	  dfs(n,0);
	  for (i = 1; i <= tot; i++) 
	    for (j = 1; j <= tot; j++)
	      g[i][j] = mtx[i][j];
	  for (m--; m > 0; m>>=1, mul(mtx, mtx, mtx))
	    if (m&1) mul(g, g, mtx);
       int aim = 0; cor(aim, 2, 1); cor(aim, n+1, 2);
 	   int64 ans = g[ask(aim)][ask(0)];
	  if (ans) printf("%I64d\n", ans);
	  else printf("Impossible\n");
    }
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章