poj2441(狀壓dp)

題目鏈接:http://poj.org/problem?id=2441,題意相當於給定n個公牛及它們各自想打的籃球場地,求取

方案數使得這n個公牛都有場地可打且這些場地均不重複。

看完《挑戰程序設計競賽》做的第一道狀態壓縮動態規劃題,狀態轉移方程相對比較好想。注意這道數據

還是比較大,亦用滾動數組~~~

一開始我是用n作爲第二維進行狀態轉移的,超時了~~~後來看了討論,便轉爲m作爲第二維,具體思路即:

f[S][j]表示前(j-1)個場地處理過達到狀態S的方案數(其中S可壓縮成一個整數,該整數的二進制位中,從右往左數

第k位若爲1,表示序號爲k的公牛已經有場地,否則該公牛未被分配場地。例如,若S=5,則其用二進制表示即

101,表示序號爲1、3的公牛已有場地,而序號爲2的未分配)

而f[S][j]=f[S][j+1](序號爲j的場地不用)+f[S'][j+1](可先處理想打第j號場地的各公牛序號,然後看S,若該公牛

未被分配場地(即相應二進制位值爲0),則可選將場地分配給其,然後S'即在S的基礎上再將該公牛標記爲

已被分配場地狀態的狀態)

注意對二進制位的一些基本操作:


1.求低到高位取n的第m位

int getBit(int n, int m){  
    return (n >> (m-1)) & 1;  
}  
2.從低到高位將n的第m位置爲1

int setBitToOne(int n, int m){  
    return n | (1 << (m-1));  
    /*將1左移m-1位找到第m位,得到000...1...000 
      n在和這個數做或運算*/  
}  
3.從低到高位將n的第m位置爲0

int setBitToZero(int n, int m){  
    return n & ~(1 << (m-1));  
    /* 將1左移m-1位找到第m位,取反後變成111...0...1111 
       n再和這個數做與運算*/  
}  
然後邊界條件即f[(1<<n)-1][m+1]=1 (所有m個場地處理過,n個公牛都被分配場地了)

再注意點循環順序~~~我的一開始一直TLE,後來改了一下,勉強過了,10s多poj上都能過,真是開掛了!

代碼如下:

import java.util.Scanner;

public class Main {
	static int n, m, num;
	static int arr[][], size[], total[], choose[][];
	static int f[];
	static boolean bo[][];

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner reader = new Scanner(System.in);
		n = reader.nextInt();
		m = reader.nextInt();
		arr = new int[n + 1][m + 1];
		size = new int[n + 1];
		bo = new boolean[n + 1][m + 1];
		for (int i = 1; i <= n; i++) {
			size[i] = reader.nextInt();
			for (int j = 1; j <= size[i]; j++) {
				arr[i][j] = reader.nextInt();
				bo[i][arr[i][j]] = true;
			}
		}
		choose = new int[m + 1][n + 1];
		total = new int[m + 1];
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= n; j++)
				if (bo[j][i]) {
					total[i]++;
					choose[i][total[i]] = j;
				}
		f = new int[1 << n];
		f[(1 << n) - 1] = 1;
		num = (1 << n) - 1;
		int num2;
		for (int i = m; i >= 1; i--) {
			for (int j = 0; j <= num; j++) {
				for (int k = 1; k <= total[i]; k++) {
					num2 = choose[i][k];
					if ((j >> (num2 - 1) & 1) == 0)
						f[j] += f[j | 1 << (num2 - 1)];
				}
			}
		}
		System.out.println(f[0]);
	}

}






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