zoj 2570 Arena DP+搜索退化贪心

题意

  N个骑士,分别有个名字和战斗值。现在一个擂台上PK,第一个人上,之后的人一个一个上。若出现替换,则次数加1.

  然后M次询问,每次一个K,问替换次数为K的序列,方案总数,以及字典序(骑士名)最小的方案输出。

解题思路

  DP优化总方案数  

    假定 p_1 < p_2 < ... < p_n

    状态dp[i][k],表示前i个骑士已经分配完策略,这个时候放 j = [ i+1, n ] 中任一个。

    当 p_j 放到 i+1 位置时, [ i+2, p-1 ] 中任意一个其实都不能替换掉 p_j , 则其在 [ i+2, n ] 这些位置可以随意放。

    则我们得出转移方程

        dp( j, k+1 ) += dp( i, k )*C( p-(i+1), n-(i+1) )*( p-(i+1) )!  

  贪心使搜索退化成O(N)不回溯

    我们可以得出一个结论,对于一个序列  p_1, p_2, p_3, ..., p_n 最大替换次数为 M

    若要求替换次数  0 <= x <= M , 总是存在的

    那么我们 按照字典序枚举满足要求的 p_i, 则p_i必定满足要求,而不需要试验其它 P_x

    所以我们可以 通过贪心 使搜索不回溯,退化成 O(N)。

 

赶脚时间复杂度也才O(N^3) 足够AC了。 可惜总方案数达到 99!, 需要FFT来优化大数乘法。

换成JAVA BigInteger 来写,却有TLE。实在无奈了。 不过跟叉姐学到了一个好的分析方式。

C/C++  WA 未处理大数

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;

typedef unsigned long long LL;

const int N = 110;
struct node{
    string name;
    int c;    
}p[N];
int mp[1010], idx;

int cmp_power( node x, node y ){
    return x.c < y.c;    
}
int cmp_name( node x, node y ){
    return x.name < y.name;    
} 
LL dp[N][N], fact[N], C[N][N];
int n, men[N];
string res[N];
bool vis[N], flag;

void init(){
    fact[0] = 1;
    for(int i = 1; i < N; i++) fact[i]=fact[i-1]*i;
    for(int i = 0; i < N; i++) C[i][0] = C[i][i] = 1;
    for(int i = 2; i < N; i++)
        for(int j = 1; j < i; j++)
            C[i][j] = C[i][j-1] + C[i-1][j-1];
}

void dfs( int m, int cur, int cnt, int num ){
    if( (cur>cnt) || flag ) return;
    if( cur == cnt && num == n ){ 
    //    for(int i = 0; i < num; i++) printf("%d ", men[i]); puts("");
        flag = true; return;}
    for(int i = 0; i < n; i++){
        if( flag ) return;
        if( !vis[i] ){
            int t_max = max( p[i].c, m );
            int t_cur = cur + (p[i].c>m);
            if( (t_cur <= cnt) &&  (n-mp[t_max] >= (cnt-t_cur)) ){
                if( (cnt==t_cur) && (n-mp[t_max]!=0) ) continue;
            //    printf("n-mp[t_max] = %d, cnt-t_cur = %d\n", n-mp[t_max], cnt-t_cur );
                men[num] = i; //printf("i = %d, t_cur = %d\n", i, t_cur );
                vis[i] = 1; 
                dfs( t_max, t_cur, cnt, num+1 );
                break;    
            }
        }    
    }
}
int main(){
    init();
    int m, c, T = 0;
    char str[30];
    while( scanf("%d",&n) != EOF){
        if( T++ > 0 ) puts("");
        memset( dp, 0, sizeof(dp));
        dp[0][0] = 1; 
        for(int i = 0; i < n; i++){
            for(int k = (i==0)?0:1; k <= i; k++){
                if( dp[i][k] <= 0 ) continue;
                for(int j = i+1; j <= n; j++){ 
                    dp[j][k+1] += dp[i][k]*C[n-(i+1)][j-(i+1)]*fact[j-(i+1)];    
                }
            }
        }
    
        for(int i = 0; i < n; i++){
            scanf("%s %d", str, &c );
            p[i].name = str; p[i].c = c;     
        }
        sort( p, p+n, cmp_power );
        for(int i = 0; i < n; i++) mp[ p[i].c ] = i+1;
        sort( p, p+n, cmp_name );
        
        int m, k;
        scanf("%d", &m);
        for(int j = 0; j < m; j++){
            scanf("%d", &k);
            if( k >= n ) printf("-_-\n");
            else{
                memset(vis, 0, sizeof(vis));
                flag = false;
                dfs( -1, -1, k, 0 );
                printf("%I64u\n", dp[n][k+1] );
                for(int i = 0; i < n; i++)
                    printf( i==0?"%s":" %s", p[ men[i] ].name.c_str() );
                puts("");
            }
        }
    }
    return 0;    
}

Java  TLE

View Code
import java.io.*;
import java.text.Bidi;
import java.util.*;
import java.math.*;
class Node{
    public String name;
    public int c;  
}

public class zoj2570 {
    
    static int N = 110;
    static int n, flag;
    static int[] vis = new int[N], men = new int[N], mp = new int[1024];
    static BigInteger[][] C = new BigInteger[N][N];
    static BigInteger[][] dp = new BigInteger[N][N];
    static BigInteger F[] = new BigInteger[N];
    static Node[] p;
    static int max(int a,int b){
        return a > b ? a : b;
    }
    public static void init(){
        F[0] = BigInteger.ONE;
        for(int i = 1; i < N; i++) F[i] = F[i-1].multiply(BigInteger.valueOf(i));
        for(int i = 0; i < N; i++ ) C[i][0] = C[i][i] = BigInteger.ONE;
        for(int i = 2; i < N; i++)
            for(int j = 1; j < i; j++ )
                C[i][j] = C[i-1][j].add( C[i-1][j-1]);
    }
    public static void dfs(int m, int cur, int cnt, int num ){
        if( flag == 1 ) return;
        if( cur == cnt && num == n ){
            flag = 1; return;
        }
        for(int i = 0; i < n; i++ ){
            if( flag == 1 ) return;
            if( vis[i] == 0 ){
                int t_cur = cur + (p[i].c > m ? 1 : 0 );
                int t_max = max( p[i].c, m );
                if( (t_cur<=num) && (n-mp[t_max]>=(cnt-t_cur)) ){
                    if( (cnt==t_cur) && (n-mp[t_max]!=0)) continue;
                    men[num] = i; vis[i] = 1;
                    dfs( t_max, t_cur, cnt, num+1 );
                    break;
                }
            }
        }
    }
    public static void main(String[] args){
        Scanner cin = new Scanner(System.in);
        int T = 0;
        init();
        while( cin.hasNext() ){
            n = cin.nextInt(); p = new Node[n];
            if( n == 0 ) break;
            if( (T++) > 0 ) System.out.println("");
            // input power and name
            for(int i = 0; i < n; i++ ){
                p[i] = new Node();
                p[i].name = cin.next();
                p[i].c = cin.nextInt();
            }
            Collections.sort(Arrays.asList(p),new Comparator<Node>(){
                public int compare( Node a, Node b ){
                    return a.c - b.c;
                }
            });
            //test
            //for(int i = 0; i < n; i++ ){
            //    if(i > 0) System.out.print(" ");
            //    System.out.print(p[i].c);
            //}System.out.println("");
            for(int i = 0; i < n; i++ ){
                mp[ p[i].c ] = i+1;
            }
            Collections.sort(Arrays.asList(p),new Comparator<Node>(){
                public int compare( Node a, Node b ){
                    return a.name.compareTo(b.name);
                }
            });
            //test
            //for(int i = 0; i < n; i++ ){
            //    if(i > 0) System.out.print(" ");
            //    System.out.print(p[i].c);
            //}System.out.println("");
            
            
            for(int i = 0; i <= n; i++)
                for(int j = 0; j <= n; j++ )
                    dp[i][j] = BigInteger.ZERO;
            dp[0][0] = BigInteger.ONE;
            for(int i = 0; i < n; i++ ){
                for(int k = (i==0)?0:1; k <= i; k++ ){
                    if( dp[i][k].compareTo(BigInteger.ZERO) <= 0 )
                        continue;
                    for(int j = i+1; j <= n; j++ ){
                        BigInteger tmp = C[n-(i+1)][j-(i+1)].multiply(F[j-(i+1)]);
                        dp[j][k+1] = dp[j][k+1].add( dp[i][k].multiply(tmp));
                    }
                }
            }
            int m = cin.nextInt(), x;
            for(int y = 0; y < m; y++){
                x = cin.nextInt();
                if( x >= n ) System.out.println("-_-");
                else{
                    for(int i = 0; i < n; i++ ) vis[i] = 0;
                    flag = 0;
                    dfs( -1,-1,x,0 );
                    System.out.println(dp[n][x+1]);
                    for(int i = 0; i < n; i++){
                        if( i > 0 ) System.out.print(" ");
                        System.out.print( p[men[i]].name );
                    }
                    System.out.println("");
                }
            }
        }
    }
}

 

posted @ 2013-04-16 21:18  yefeng1627  阅读(201)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor