男人八题总结

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 ;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值