zoukankan      html  css  js  c++  java
  • 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("");
                    }
                }
            }
        }
    }
  • 相关阅读:
    把java程序作为windows服务运行
    安装CentOS7出现dracut-initqueue timeout-starting…starting timeout scripts 解决办法
    在Linux下打包tar文件时添加密码的方法
    tk mybatis通用mapper,复杂and or条件查询
    firewalld 端口转发(机器内转发+机器间转发)
    postgresql中的序列nextval
    postgresql 建立索引
    索引面试题分析
    PostgreSQL不等于查询索引方法
    net-snmp开发中出现“Error opening specified endpoint"" ”的解决方案
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3024915.html
Copyright © 2011-2022 走看看