• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            算法學(xué)社
            記錄難忘的征途
            posts - 141,comments - 220,trackbacks - 0
            這場(chǎng)只出了一道題,掉了很多分。D題和E題近期補(bǔ)上。

            A

            題目描述:
               有N(N<200)項(xiàng)工作。每項(xiàng)工作必須在一個(gè)模式下花費(fèi)1個(gè)單位時(shí)間完成,工作之間的完成順序存在依賴關(guān)系,形成DAG圖。一共有三種模式(0,1,2)。模式之間的切換時(shí)間為
            [0,1,2]
            [2,0,1]
            [1,2,0]
            一開(kāi)始你可以0花費(fèi)選擇一種模式,問(wèn)完成所有工作的最少時(shí)間。

            算法分析:
               拓?fù)渑判?貪心法。
               假設(shè)我目前在模式A,那么第一步一定要一口氣把A模式的任務(wù)全都完成。
               然后要選擇模式切換代價(jià)較小的模式。因?yàn)檫@樣的模式最多只有一種,所以就可以輕松解決了。
            #include<iostream>
            #include<cstdio>
            #include<cstring>
            using namespace std;
            const int flag[3][3] = {
                {0,1,2},{2,0,1},{1,2,0}
            };
            const int N = 205;
            int num[N] , G[N][N], Du[N], tmp[N],vis[N],n;
            int work(int p){
            //    cout<<"p: "<<p<<endl;
                int v = 0,f = 0;
                while(1){
                    f = 0;
                    for(int i=0;i<n;i++) if(!Du[i] && !vis[i] && num[i] == p){
            //            cout<<i<<" ";
                        vis[i] = 1;
                        v++;
                        for(int v=0;v<n;v++) if(!vis[v] && G[i][v]) 
                            Du[v]--;
                        f = 1;
                    }
                    if(!f) break;
                }
            //    cout<<endl;
                for(int i=0;i<n;i++) if(!Du[i] && !vis[i] && flag[p][num[i]] == 1){
                    v += 1 + work(num[i]);
                    return v;
                }
                for(int i=0;i<n;i++) if(!Du[i] && !vis[i]) {
                    v += 2 + work(num[i]);
                    return v;
                }
                return v;
            }
            int main(){
                while( cin >> n){
                    for(int i=0;i<n;i++)
                        for(int j=0;j<n;j++)
                            G[i][j] = 0;
                    for(int i=0;i<n;i++){
                        scanf("%d",&num[i]);
                        num[i]--;
                    }
                    int t;
                    memset(tmp,0,sizeof(tmp));
                    for(int i=0;i<n;i++){
                        cin >> tmp[i];
                        for(int oo=0;oo<tmp[i];oo++){
                            int u;
                            cin >> u;
                            u --;
                            G[u][i] = 1;
                        }
                    }
                    int ans = ~0u>>2;
                    for(int p=0;p<3;p++)
                        for(int i=0;i<n;i++)
                            if(!tmp[i] && p == num[i]){
                                memset(vis,0,sizeof(vis));
                                for(int i=0;i<n;i++) Du[i] = tmp[i];
                                int v =work(p);
            //                    cout<<"ans: "<<p<<" "<<v<<endl;
                                if(v<ans) ans = v;
                                break;
                            }
                    cout<< ans << endl;
                }
            }

            B

            給出一個(gè)序列a[10](a[i]<100),和N(N<100)。構(gòu)造一個(gè)長(zhǎng)度為N的數(shù)字,要求
               1.沒(méi)有前導(dǎo)0
               2.數(shù)字i不少于a[i]個(gè)
            求構(gòu)造方法數(shù)。

            算法分析:
               典型的動(dòng)態(tài)規(guī)劃求解。
               dp[i][j]表示前j個(gè)數(shù)字構(gòu)成符合條件的長(zhǎng)度為i的數(shù)字的方法數(shù)。
               顯然dp[i][j] = sum(dp[k][j-1] * C[i][k]) 其中k>0 && k<=i-a[j]
               組合數(shù)預(yù)處理出來(lái)即可,其中要考慮轉(zhuǎn)移0的問(wèn)題,這個(gè)留給大家思考吧~~

            #include<iostream>
            #include<cstdio>
            using namespace std;
            const int mod = (int)1e9 + 7;
            typedef long long ll;
            const int N = 105;
            ll C[N][N];
            void OP(int msk){
                for(int i=0;i<10;i++, msk>>=1)
                    cout<<(msk&1);cout<<" ";
            }
            int main(){
                for(int i=0;i<N;i++) {
                    C[i][0] = 1;
                    for(int j=1;j<=i;j++)
                        C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod;
                }
                int n, a[11];
                static ll dp[N][1<<11];
                while(cin >> n){
                    for(int i=0;i<10;i++){
                        cin >> a[i];
                    }
                    dp[0][0] =1;
                    for(int i = 0; i<=n; i++){
                        for(int msk = 1; msk < (1<<10); msk++){
                            ll &t = dp[i][msk] ;
                            t = 0;
                            for(int p = 0; p < 10; p++) if((1<<p) & msk){
                                ll s = 0;
                                for(int j=0;j<=i-a[p];j++){
                                    if(p) s += C[i][i-j] * dp[j][msk^(1<<p)];
                                    else s += i ?C[i-1][i-j]*dp[j][msk^(1<<p)] : 0;
                                    s %= mod;
                                    if(s){
            //                            cout<<i<<" ";OP(msk);cout<<j<<" "<<p<<" "<<dp[j][msk^(1<<p)]<<endl;
            //                            cout<<s<<endl;
                                    }
                                }
                                t = (t+s) % mod;
                                break;
                            }
                        }
                    }
                    ll ans = 0;
                    for(int i = 1; i<=n; i++)
                        ans = (ans + dp[i][(1<<10)-1]) % mod;
                    cout<< ans << endl;
                }
            }

            C

            給一個(gè)N*N的矩陣(N<300),權(quán)值范圍是[-1000,1000]。現(xiàn)在讓你從右上角走到左下角,只能向下或者向右走,走兩次,每個(gè)格子最多取一次權(quán)值,問(wèn)最大能取到的值是多少。

            算法分析:

            因?yàn)楦褡由系臋?quán)值可能是負(fù)數(shù),所以費(fèi)用流ggg。
            考慮動(dòng)態(tài)規(guī)劃,想像兩次是兩個(gè)人a,b同時(shí)走的,在走了i步之后,a的x值是xa,b的x值是xb。
            dp[i][xa][xb]記為此時(shí)可以獲取的最大權(quán)值。
            轉(zhuǎn)移就很簡(jiǎn)單了,呵呵~

            #include<iostream>
            #include<cstdio>
            using namespace std;
            const int N = 305;
            int dp[2][N][N], num[N][N],n;
            const int inf = ~0u>>2;
            inline bool chk(int x,int y){
                return x >=0 && y >=0 && x <n && y <n;
            }
            inline void chkmax(int &a,const int b){if(a<b)a=b;}
            int main(){
                while(cin >> n){
                    for(int i=0;i<n;i++)
                        for(int j=0;j<n;j++)
                            cin >> num[i][j] ;
                    int ans = (dp[0][0][0] = num[0][0]);
                    for(int i=1;i<2*n-1;i++) 
                        for(int p = (i>=n)? i-n+1: 0; p < min(n,i+1); p++) {
                            for(int q = p; q< min(n,i+1); q++) {
                                int v;
                                if(q == p) v = num[p][i-p];
                                else v = num[p][i-p] + num[q][i-q];
                                dp[i&1][p][q] = -inf;
                                for(int oo = 0; oo<2;oo++){
                                    int nx1 = p - (oo==0);
                                    int ny1 = i-p - (oo==1);
                //                    cout<<nx1<<" "<<ny1<<endl;
                                    if(!chk(nx1,ny1)) continue;
                                    for(int uu = 0; uu<2; uu++){
                                        int nx2 = q - (uu==0);
                                        int ny2 = i-q - (uu==1);
                //                        cout<<nx2<<" "<<ny2<<endl;
                                        if(!chk(nx2,ny2)) continue;
                                        int x1 = nx1,x2 =nx2;
                                        if(x1>x2) swap(x1,x2);
                //                        if(p==q)    cout<<p<<" "<<i-p<<" "<<nx1<<" "<<nx2<<endl;
                                        chkmax(dp[i&1][p][q], dp[i-1&1][x1][x2] + v);
                                    }
                                }
                                ans = dp[i&1][p][q];
            //                    if(p==q)    cout<<"i: "<<i<<" "<<p<<" "<<q<<" "<<ans<<endl;
                            }
                        }
                    cout << ans << endl;
                }
                return 0;    
            }




            posted on 2012-08-03 15:36 西月弦 閱讀(286) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 解題報(bào)告
            国产成人久久久精品二区三区| 精品久久人人爽天天玩人人妻| 夜夜亚洲天天久久| 99久久精品免费国产大片| 亚洲欧美精品一区久久中文字幕 | 久久99久久99小草精品免视看 | 99久久国产综合精品五月天喷水| 日产久久强奸免费的看| 狠狠88综合久久久久综合网| 品成人欧美大片久久国产欧美| 久久免费看黄a级毛片| 精品国产91久久久久久久a| 亚洲精品tv久久久久| 久久午夜电影网| 浪潮AV色综合久久天堂| 香蕉99久久国产综合精品宅男自 | 久久久久99精品成人片| 久久久久亚洲av成人无码电影| 超级97碰碰碰碰久久久久最新| 久久国产精品成人影院| 国产激情久久久久久熟女老人 | 久久WWW免费人成—看片| 久久久久人妻一区精品色| 亚洲欧洲精品成人久久奇米网| 国产成人精品免费久久久久| 久久人人爽人人爽人人片AV高清| 国产成人精品综合久久久| 2021久久国自产拍精品| 久久综合狠狠综合久久| 久久久噜噜噜久久中文字幕色伊伊| 久久这里有精品视频| 国产高清国内精品福利99久久| 99久久精品毛片免费播放| 麻豆亚洲AV永久无码精品久久| 色天使久久综合网天天| A级毛片无码久久精品免费| 久久亚洲sm情趣捆绑调教| 超级97碰碰碰碰久久久久最新| 久久久国产99久久国产一| 2021国内精品久久久久久影院| 日本欧美国产精品第一页久久|