POJ 1737 统计有n个顶点的连通图有多少个 (带标号)
设f(n)为所求答案
g(n)为n个顶点的非联通图
则f(n) + g(n) = h(n) = 2^(n * (n - 1) / 2)
其中h(n)是n个顶点的联图的个数
先考虑1所在的连通分量包含哪些顶点
假设该连通分量有k个顶点
就有C(n - 1, k - 1)种集合
确定点集后,所在的连通分量有f(k)种情况。其他连通分量有 h(n - k)种情况
因此有递推公式。g(n) = sum{ C(n - 1, k - 1) * f(k) * h(n - k)} 其中k = 1,2...n-1
注意每次计算出g(n)后立刻算出f(n)
import java.util.*;
import java.math.*;
public class Main {
public static final int N = 50 ;
public static BigInteger g[] = new BigInteger[N+1] ;
public static BigInteger f[] = new BigInteger[N+1] ;
public static BigInteger h[] = new BigInteger[N+1] ;
public static BigInteger C[][] = new BigInteger[N+1][N+1] ;
public static BigInteger MyPow(BigInteger x , int y){
BigInteger ans = BigInteger.ONE ;
for(; y > 0 ; y >>= 1){
if((y & 1) == 1) ans = ans.multiply(x) ;
x = x.multiply(x) ;
}
return ans ;
}
public static void GetC(){
int i , j ;
C[1][0] = C[1][1] = BigInteger.ONE ;
for(i = 2 ; i <= N ; i++){
C[i][0] = C[i][i] = BigInteger.ONE ;
for(j = 1 ; j < i ; j++)
C[i][j] = C[i-1][j-1].add(C[i-1][j]) ;
}
}
public static void GetH(){
int i ;
h[1] = BigInteger.ONE ;
for(i = 2 ; i <= N ; i++)
h[i] = MyPow(BigInteger.valueOf(2), C[i][2].intValue()) ;
}
public static void GetF(){
int n , k ;
f[1] = BigInteger.ONE ;
for(n = 2 ; n <= N ; n++){
g[n] = BigInteger.ZERO ;
for(k = 1 ; k <= n-1 ; k++){
g[n] = g[n].add(C[n-1][k-1].multiply(f[k]).multiply(h[n-k])) ;
}
f[n] = h[n].subtract(g[n]) ;
}
}
public static void main(String[] args) {
GetC() ;
GetH() ;
GetF() ;
Scanner cin = new Scanner(System.in) ;
while(cin.hasNext()){
int n = cin.nextInt() ;
if(n == 0) break ;
System.out.println(f[n]);
}
}
}
POJ 1742 coins
多重背包问题,用n个物品,每个物品有价值v[i],每个物品数量限制为c[i]
这道题是问,用所有的硬币能够在m的范围内最多可以组合成多少种价值
const int Max_N = 100008 ;
int V ;
bool dp[Max_N] ;
void ZoreonePack(int v , int w){
for(int i = V ; i >= v ; i--)
dp[i] |= dp[i-v] ;
}
void CompletePack(int v , int w){
for(int i = v ; i <= V ; i++)
dp[i] |= dp[i-v] ;
}
int a[Max_N] , c[Max_N] ;
int N ;
int DP(){
int i , j , x , ans = 0 ;
memset(dp , 0 , (1+V)*sizeof(bool)) ;
dp[0] = 1 ;
for(i = 1 ; i <= N ; i++){
if(a[i] * c[i] >= V)
CompletePack(a[i] , a[i]) ;
else{
x = 1 ;
while(c[i] >= x){
ZoreonePack(a[i]*x , a[i]*x) ;
c[i] -= x ;
x <<= 1 ;
}
if(c[i] > 0)
ZoreonePack(a[i]*c[i] , a[i]*c[i]) ;
}
}
for(i = 1 ; i <= V ; i++)
ans += dp[i] ;
return ans ;
}
int main(){
while(scanf("%d%d" ,&N ,&V)){
if(N == 0 && V == 0) break ;
for(int i = 1 ; i <= N ; i++) scanf("%d" ,&a[i]) ;
for(int i = 1 ; i <= N ; i++) scanf("%d" ,&c[i]) ;
printf("%d\n" , DP()) ;
}
return 0 ;
}