zoukankan      html  css  js  c++  java
  • CF 295C Greg and Friends DP

    題目:
    有50斤的人c1人,100斤的人c2人。現在他們需要過河,但是只有一條船,並且船的載重重量不超過k。問有多少種方法
    使得運人過河的次數最少。

    分析:
    三維DP。
    由於從河的對岸過來以及過去河的對岸是等價的,所以我們直接考慮單次過河的情況。
    dp[i][x][y]表示第i次過河,過河之後對岸有50斤的人x,100斤的人y的方法數。

    我們假設第n次過河的人的個數為i,j,過河前河岸有x,y人,所以過完河之後河的對岸有c1-x+i,c2-y+j人。
    所以轉移方程為
    dp[n][c1-x+i][c2-y+j] += dp[n-1][x][y]*comb[x][i]*comb[y][j];
    comb[x][y]表示從x人裏面選擇y個人過河的組合數。

    需要注意每次過河的人數必須大於0並且不能夠超載。
    運算過程中需要模1e9+7以防爆long long。
    另外我們可以用滾動數組來減少內存。
    運輸的最大次數不能夠超過2*n次,否則無解。
    我們假設有2個50,一個100的,載重量上線為100,根據題目的提示知道,需要運送5次才能夠把這幾個運輸
    到河的對岸。所以每運輸一個100的,需要利用兩個50的額外多運輸2次,總的來說最多運送2*n次。

    #include <set>
    #include <map>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <string>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    
    #define lx(x) (x<<1)
    #define rx(x) (x<<1|1)
    #define debug puts("here")
    #define rep(i,n) for(int i=0;i<n;i++)
    #define rep1(i,n) for(int i=1;i<=n;i++)
    #define REP(i,a,b) for(int i=a;i<=b;i++)
    #define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)
    #define pb push_back
    #define RD(n) scanf("%d",&n)
    #define RD2(x,y) scanf("%d%d",&x,&y)
    #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w)
    
    /******** program ********************/
    
    const int MOD = 1e9+7;
    const int MAXN = 51;
    
    ll comb[MAXN][MAXN],dp[2][MAXN][MAXN];
    int c1,c2,n,num,old,now;
    
    void solve(){
        swap(now,old);
        memset(dp[now],0,sizeof(dp[now]));
    
        rep(i,c1+1) /// 當前有i,j人過河
            rep(j,c2+1) if( (i+j*2) && i+j*2<=num ) /// 有人過河並且過河的人的重要不能夠超過載重
                REP(x,i,c1) /// 河岸有x,y人,我們可以算出河的對岸有多少人
                    REP(y,j,c2)
                        dp[now][c1-x+i][c2-y+j] += dp[old][x][y]*comb[x][i]%MOD*comb[y][j]%MOD;
    }
    
    int main(){
    
    #ifndef ONLINE_JUDGE
    	freopen("sum.in","r",stdin);
    	//freopen("sum.out","w",stdout);
    #endif
    
        rep(i,51){
            comb[i][0] = 1;
            rep1(j,i)
                comb[i][j] = (comb[i-1][j]+comb[i-1][j-1])%MOD;
        }
    
        while(~RD2(n,num)){
            num /= 50;
    
            int x;
            c1 = c2 = 0;
            rep(i,n){
                RD(x);
                c1 += x==50;
                c2 += x==100;
            }
    
            memset(dp,0,sizeof(dp));
            old = 1,now = 0;
            dp[now][c1][c2] = 1;
            bool ok = false;
    
            rep(i,2*n){
                solve(); // 運送過河
                if(dp[now][c1][c2]){
                    cout<<i*2+1<<endl;
                    cout<<dp[now][c1][c2]%MOD<<endl;
                    ok = true;
                    break;
                }
                solve(); // 從河的對岸運送回來,兩者等價
            }
            if(!ok)
                puts("-1\n0");
        }
    
    	return 0;
    }
    

      

  • 相关阅读:
    Python基础篇 -- 列表
    Python基础篇 -- 字符串
    Python基础篇 -- if while 语句
    Python基础篇 -- 运算符和编码
    Python 入门基础
    Docker知识收藏
    秒表
    Emac
    Android开发
    shell 小工具
  • 原文地址:https://www.cnblogs.com/yejinru/p/3021521.html
Copyright © 2011-2022 走看看