• <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>

            M.J的blog

            algorithm,ACM-ICPC
            隨筆 - 39, 文章 - 11, 評論 - 20, 引用 - 0
            數(shù)據(jù)加載中……

            此blog廢掉啦~

                   請?jiān)L問http://www.orzminjie.info/

            posted @ 2010-12-08 22:59 M.J 閱讀(247) | 評論 (0)編輯 收藏

            求樹的直徑

                          樹的直徑是指樹的最長簡單路。求法: 兩遍BFS :先任選一個(gè)起點(diǎn)BFS找到最長路的終點(diǎn),再從終點(diǎn)進(jìn)行BFS,則第二次BFS找到的最長路即為樹的直徑;
                          原理: 設(shè)起點(diǎn)為u,第一次BFS找到的終點(diǎn)v一定是樹的直徑的一個(gè)端點(diǎn)
                          證明: 1) 如果u 是直徑上的點(diǎn),則v顯然是直徑的終點(diǎn)(因?yàn)槿绻鹶不是的話,則必定存在另一個(gè)點(diǎn)w使得u到w的距離更長,則于BFS找到了v矛盾)
                                  2) 如果u不是直徑上的點(diǎn),則u到v必然于樹的直徑相交(反證),那么交點(diǎn)到v 必然就是直徑的后半段了
                                   所以v一定是直徑的一個(gè)端點(diǎn),所以從v進(jìn)行BFS得到的一定是直徑長度

                          相關(guān)題目有TOJ1056,TOJ3517.

            TOJ 1056(Labyrinth):
                    大意是一個(gè)由‘#’和'.'構(gòu)成的迷宮,'.'表示可行,‘#’表示不可行,問可行的最長的路的長度是多少。

            #include <cstdio>
            #include 
            <cstring>
            #include 
            <queue>
            #define M 1002

            using namespace std;

            int r,c;
            char map[M][M];
            bool flag[M][M];
            int move[4][2]={-1,0,1,0,0,-1,0,1};                                               // 分別表示上下左右
            int maxt;
            struct Node{
                    
            int x,y,num;
            };
            Node ans;
            bool legal(int x,int y){                                                                   //判斷該點(diǎn)是否越界及是否可走
                    if(x >=0 && x < r && y>=0 && y < c &&map[x][y]=='.'return true;
                    
            return false;
            }
            void bfs(Node start){
                    memset(flag,
            false,sizeof(flag));                                               //初始所有點(diǎn)標(biāo)記為false
                    flag[start.x][start.y] = true;                                                    //起點(diǎn)標(biāo)記為true
                    queue<Node>f;
                    
            while(!f.empty()) f.pop();                                                       //清空創(chuàng)建的隊(duì)列
                    Node m,n,tep;
                    
            int tx,ty,xx,yy;
                    
            int i,j,k,num;
                    f.push(start);
                    
            while(!f.empty()){                                                                   //如果隊(duì)列不為空
                            m = f.front();                                                                   //取出隊(duì)首元素
                            tx = m.x; ty = m.y; num = m.num;
                            
            if(num > maxt){                                                              //如果該元素的長度大于maxt,更新maxt
                                    maxt = num;
                                    ans 
            = m;
                            }
                            
            for(i = 0;i < 4; i++){                                                       //以m為起點(diǎn)向4個(gè)方向BFS
                                    xx = tx + move[i][0];
                                    yy 
            = ty + move[i][1];
                                    
            if(!flag[xx][yy] && legal(xx,yy)){
                                            flag[xx][yy] 
            = true;
                                            tep.x 
            = xx;
                                            tep.y 
            = yy;
                                            tep.num 
            = num + 1;
                                            f.push(tep);
                                            
            if(num+1>maxt){                                            //如果有更大的則更新
                                                    maxt = num + 1;
                                                    ans 
            = tep;
                                            }
                                    }
                            }
                            f.pop();                                                                              
            //彈出隊(duì)首元素
                    } 
            }
            int main(){
                    
            int i,j,T;
                    Node start,end;
                    
            bool mark;
                    scanf(
            "%d",&T);
                    
            while(T--){
                            scanf(
            "%d%d",&c,&r);
                            mark 
            = false; maxt = -1;
                            
            for(i = 0;i < r; i++)
                                    scanf(
            "%s",map[i]);
                            
            for(i = 0;i < r; i++){
                                    
            for(j = 0;j < c; j++){
                                            
            if(map[i][j]=='.'){                                                     //任選一點(diǎn)BFS
                                                    start.x = i;
                                                    start.y 
            = j;
                                                    start.num 
            = 0;
                                                    bfs(start);
                                                    mark 
            = true;
                                                    
            break;
                                            }
                                    }
                                    
            if(mark) break;
                            }
                            maxt 
            = -1;ans.num = 0;                                                           //此時(shí)ans一定是直徑的端點(diǎn),將它設(shè)為起點(diǎn)
                            bfs(ans);                                                                                    //進(jìn)行第二次BFS
                            printf("Maximum rope length is %d.\n",maxt);
                    }
            }


            TOJ3517(The longest athletic track):
                      題目給出了一棵生成樹,問這棵生成樹最長的路的長度是多少。

            #include<iostream>
            #include
            <queue>
            #define INF 999999
            #define M 2002
            using namespace std;
            int n;
            int maxx;
            int map[M][M],sum[M];
            bool flag[M];
            int bfs(int begin){
                        queue
            <int>f;
                       
            int i,m,k,key;
                        maxx
            =0;
                        memset(flag,
            false,sizeof(flag));
                        f.push(begin);
                       
            while(!f.empty()){
                                    k
            =f.front();
                                    
            for(i=1;i<=n;i++){
                                            
            if(map[k][i]!=INF&&!flag[i]){
                                                        flag[i]
            =true;
                                                        f.push(i);
                                                        sum[i]
            =sum[k]+map[k][i];
                                                        
            if(sum[i]>maxx) { maxx=sum[i];key=i; }
                                             }
                                     }
                                     f.pop();
                        }
                       
            return key;
            }
            int main()
            {
                       
            int i,j,k,dis,key,cas;
                        scanf(
            "%d",&cas);
                       
            while(cas--){
                                     scanf(
            "%d",&n);
                                    
            for(i=1;i<n;i++)
                                              
            for(j=i+1;j<=n;j++)
                                                        map[i][j]
            =map[j][i]=INF;
                                    
            for(i=1;i<n;i++){
                                               scanf(
            "%d%d%d",&j,&k,&dis);
                                               map[j][k]
            =map[k][j]=dis;
                                     }
                                     sum[
            1]=0;
                                     key
            =bfs(1);
                                     sum[key]
            =0;
                                     key
            =bfs(key);
                                     printf(
            "%d\n",maxx);
                         }
                
            //system("pause");
            }





            posted @ 2010-07-08 01:14 M.J 閱讀(2653) | 評論 (0)編輯 收藏

            歸并排序求逆序?qū)?/a>

                          早就想學(xué)一下歸并排序求逆序?qū)Γ谶@之前只會(huì)用樹狀數(shù)組來做,有時(shí)候還需要離散化,而且效率還不如歸并排序高。
                          其實(shí)還是蠻簡單的,知道歸并排序的原理就很容易知道如何求逆序?qū)α恕TO(shè)數(shù)組為A,關(guān)鍵是在合并的時(shí)候,用數(shù)組L 和 R 表示左右兩個(gè)子數(shù)組,因?yàn)槟嫘驅(qū)Φ膫€(gè)數(shù)f(A) = f(L) + f(R) + s(L,R);其中f(L) 和 f(R) 分別表示L 內(nèi)部 和R內(nèi)部的逆序?qū)€(gè)數(shù),s(L.R)表示大數(shù)在L,小數(shù)在R的逆序?qū)ΑR驗(yàn)長和R是已經(jīng)排好序的,故其實(shí)只需求s(L,R).這個(gè)可以在合并L和R依次進(jìn)行比較的時(shí)候算出。
            for(k = p;k <= r;k ++){
                     
            if(L[i]<=R[j])
                              a[k] 
            = L[i++];
                     
            else{                                                //如果L最上面的數(shù)大于R的,那么L[i]及后面的數(shù)可以和R[j]構(gòu)成n1-i+1個(gè)逆序?qū)?br>                  a[k] = R[j++];
                              count 
            +=(n1 -+ 1);              //累加
                      }
            }

            歸并排序的代碼:

            void merge(int p,int q,int r){
                     
            int n1 = q-p+1,n2 = r-q;
                     
            int i,j,k;
                     
            for(i = 1;i <= n1; i++)
                               L[i] 
            = a[p+i-1];
                     
            for(j = 1;j <= n2; j++)
                               R[j] 
            = a[q+j];
                      L[n1
            +1= INF;
                      R[n2
            +1= INF;
                      i 
            = 1;j = 1;
                     
            for(k = p;k <= r;k ++){
                              
            if(L[i]<=R[j])
                                         a[k] 
            = L[i++];
                              
            else{
                                         a[k] 
            = R[j++];
                                         count 
            +=(n1 -+ 1);
                               }
                      }
            }
            void merge_sort(int p,int r){
                     
            if(p<r){
                              
            int q = (p+r)/2;
                               merge_sort(p,q);
                               merge_sort(q
            +1,r);
                               merge(p,q,r);
                      }
            }


            posted @ 2010-07-08 00:07 M.J 閱讀(2710) | 評論 (1)編輯 收藏

            多重背包問題

            今天看了下多重背包,理解的還不夠深入,不過因?yàn)槭?1背包過來的,所以接受起來很容易。
            主要是運(yùn)用了二進(jìn)制的思想將一個(gè)數(shù)量為N很大的物品分為了logN個(gè)數(shù)量小的物品,而這logN個(gè)物品可以組成數(shù)量為0到N任意數(shù)量,所以這種策略是
            成立的。
            多重背包問題有TOJ1034,TOJ1670.

            TOJ1034 :
            大意是有6種規(guī)格的石頭,編號從1到6,編號為 i 的石頭的價(jià)值為 i .現(xiàn)在給出各種石頭的數(shù)量,問有沒有可能得到總價(jià)值的一半。
            做法:    DP, 每種石頭價(jià)值為v[i],價(jià)值為 i ,數(shù)量為 num[i] ,通過多重背包看能不能恰好取得總價(jià)值的一半。
                       一個(gè)優(yōu)化是總價(jià)值為奇數(shù)直接不用考慮,而在DP的時(shí)候設(shè)置一個(gè)標(biāo)記來記錄是否已經(jīng)取得總價(jià)值一半,如果取得則可以返回。
            做法2:這種方法的前提是POJ  discuss里的一種做法,即給每個(gè)石頭的數(shù)量mod 8。證明是用抽屜原理證的,很復(fù)雜,我沒有看。但是這樣以來,數(shù)量
                        一下子大大減少,極大的提高了效率。
                        我說的做法2事實(shí)上是我的最初做法,即DFS,搜索,在搜索過程中注意剪枝,再加上數(shù)量取模的優(yōu)化,復(fù)雜度也不高。 

            Code for 1034(Dividing):
            import java.util.Scanner;

            import java.util.
            *;

            import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MaximizeAction;
            public class Main {
                
            public static int f[] = new int[20001*6];                                                // f[i]表示容量為 i 的背包最多能裝的物品的價(jià)值
                
            public static int v[] = new int[7];
                
            public static int num[] = new int[7];
                
            public static int total,flag,key;                                                               //total為 6 種大理石的總價(jià)值 ,flag為標(biāo)記,一旦為1表示可以取得,可以返回了
                
            public static void onezeropack(int cost,int weight) {                           //  01背包函數(shù),注意循環(huán)是從total 到 cost,不要弄反
                         
            int i;
                         
            for(i = total;i >= cost; i--) {
                                    f[i] 
            = Math.max(f[i],f[i-cost]+weight);
                                   
            if(f[i] == key) {                                                                 // 如果可以取得總價(jià)值一半,flag=1,返回
                                              flag 
            = 1;
                                             
            return ;
                                    }
                          }
                }
                
            public static void finishpack(int cost,int weight) {                            
                         
            int i;
                         
            if(flag==1return ;
                         
            for(i = cost;i <= total; i++) {
                                     f[i] 
            = Math.max(f[i], f[i-cost]+weight);
                                   
            if(f[i] == key) {
                                            flag 
            = 1;
                                           
            return ;
                                    }
                          }
                }
                
            public static void multipack(int cost,int weight,int amount) {
                            
            if(cost*amount >= total) {
                                        finishpack(cost, weight);
                                       
            return ;
                             }
                            
            if(flag==1return ;
                            
            int k = 1;
                            
            while(k < amount) {                                                                                        // 該過程即為將一件物品拆分為1,2,4...2^k 件物品進(jìn)行01背包過程
                                        onezeropack(k
            *cost, k*weight);
                                        amount 
            -= k;
                                        k 
            *= 2;
                             }
                             onezeropack(cost
            *amount, weight*amount);
                }
                
            public static void main(String[] args){
                             Scanner 
            in = new Scanner(System.in);
                            
            int i,j,cas = 1;
                            
            while(true) {
                                        Arrays.fill(f,
            0);
                                        total 
            = 0; flag = 0;
                                       
            for(i = 1;i <= 6; i++) {
                                                   num[i] 
            = in.nextInt();
                                                   v[i] 
            = i;
                                                   total 
            += i*num[i];
                                        }
                                      
            if(num[1]==0&&num[2]==0&&num[3]==0&&num[4]==0&&num[5]==0&&num[6]==0)
                                                 
            break;
                                      
            if(total%2==1) flag = 0;
                                      
            else {
                                                 key 
            = total/2;
                                                
            for(i = 1;i <= 6; i++
                                                 multipack(i, i, num[i]);
                                       }
                                       System.
            out.println("Collection #"+cas+":");
                                      
            if(flag==0) System.out.println("Can't be divided.");
                                      
            else System.out.println("Can be divided.");
                                       System.
            out.println();
                                       cas
            ++;
                            }
                }

            }

            TOJ 1670:
                      大意是一臺取款機(jī)有N中貨幣,每種貨幣面值為 V[i] ,數(shù)量為 num[i] , 給出一個(gè)價(jià)值,為在這個(gè)價(jià)值之內(nèi)(包括這個(gè)價(jià)值)最大能取得多大。
            分析:典型的多重背包,給出的價(jià)值即為背包容量,每種貨幣為一種物品,價(jià)值為v[i] , 數(shù)量為num[i],求能得到的最大價(jià)值。
                      注釋就不加了,參考上面的程序

            Code for 1670(Cash Mechine):

            #include <cstdio>
            #include 
            <cstring>

            int f[100002],v[12],num[12],cost[12];
            int total,n;
            int max(int a,int b){ return a>b?a:b;}

            void OneZeroPack(int cost,int value){
                      
            int i,j;
                      
            for(i = total;i >= cost; i--)
                               f[i] 
            = max(f[i],f[i-cost]+value);

            }
            void completePack(int cost,int weight){
                      
            int i;
                      
            for(i = cost;i <= total; i++)
                               f[i] 
            = max(f[i],f[i-cost]+weight);
            }
            void multiPack(int cost,int weight,int amount){
                      
            if(cost*amount >= total){
                               completePack(cost,weight);
                              
            return ;
                       }
                      
            int k = 1;
                      
            while(k < amount){
                               OneZeroPack(k
            *cost,k*weight);
                               amount 
            -= k;
                               k
            *=2;
                       }
                       OneZeroPack(cost
            *amount,amount*weight);
            }
            int main(){
                      
            int i,j,k;
                      
            while(scanf("%d%d",&total,&n)!= EOF){
                               memset(f,
            0,sizeof(f));
                      
            for(i = 1;i <= n; i++){
                               scanf(
            "%d%d",&num[i],&cost[i]);
                               v[i] 
            = cost[i];
                       }
                      
            for(i = 1;i <= n; i++)
                               multiPack(cost[i],v[i],num[i]);
                               printf(
            "%d\n",f[total]);    
                       }
            }



            posted @ 2010-07-07 20:18 M.J 閱讀(785) | 評論 (0)編輯 收藏

            TOJ 3446.Money Matters 并查集,路徑壓縮

                    題目大意是N個(gè)人互相有債a[i](正的表示別人欠錢,否則表示自己欠別人錢,a[i]的和保證為0),但是這N個(gè)人只有朋友間才能互相算帳,現(xiàn)在給出N個(gè)人的債,并且給出M個(gè)關(guān)系,即誰和誰是朋友,最后問有沒有可能所有人都把帳算清。


            Sample Input 1:                         Sample Input 2:

            5    3                                            4     2
            100                                              15
            -75                                               20
            -25                                              -10
            -42                                              -15
            42                                                0  2
            0 1                                               1  3
            1 2
            3 4

            Sample Output 1:                       Sample Output  2:

            POSSIBLE                                    IMPOSSILBE

             思路1:

                          每輸入一個(gè)關(guān)系,合并,最后從1到N,對于每一個(gè)人,找出它們的祖先,將他們的債debt加到祖先的debt

                          上。通俗的講,就是每個(gè)集合的成員都將自己的debt加到祖先上,自己歸0,最后看祖先的值是否為0;

                          最后在從1到N掃一遍如果有debt不為0的,輸出“IMPOSSIBLE”,否則“POSSIBLE”;

                          缺點(diǎn):復(fù)雜度高,查詢復(fù)雜度*N,最后勉強(qiáng)過了,時(shí)間0.63s

            思路2:

                          路徑壓縮,每輸入一個(gè)關(guān)系,合并。最后從1到N,如果 i 的debt不為0,從 i 到 i 的祖先的路徑不斷壓縮直到

                          祖先,這樣雖然仍然是N次操作,但由于在壓縮過程中大部分成員debt歸0,故實(shí)際上進(jìn)行操作的次數(shù)遠(yuǎn)小于N.

                          最后時(shí)間為0.11,比起上一種方法有了很大提高

            Code 1:

            #include <cstdio>
            #include 
            <cstring>
            struct Node{
                    
            int father,v,num;
            }a[
            10002];
            int find(int n){
                    
            int tep,m = n;
                    
            while(n != a[n].father)
                            n 
            = a[n].father;
                    
            while(m != n){
                            tep 
            = a[n].father;
                            a[n].father 
            = n;
                            m 
            = tep;
                    }
                    
            return n;
            }
            void Union(int root1,int root2){
                    
            int t1,t2;
                    t1 
            = find(root1),t2 = find(root2);
                    
            if(t1 == t2) return ;
                    
            else{
                            
            if(a[t1].v > a[t2].v){
                                    a[t1].v 
            += a[t2].v;
                                    a[t2].father 
            = t1;
                            }
                            
            else{
                                    a[t2].v 
            += a[t1].v;
                                    a[t1].father 
            = t2;
                            }
                    }
            }
            int main()
            {
                    
            int n,m,i,j;
                    
            bool flag = false;
                    scanf(
            "%d%d",&n,&m);
                    
            for(i = 0;i < n; ++i){
                            a[i].father 
            = i,a[i].v = 0;
                            scanf(
            "%d",&a[i].num);
                    }
                    
            while(m--){
                            scanf(
            "%d%d",&i,&j);
                            Union(i,j);
                    }
                    
            for(i = 0;i < n; ++i){
                            
            int tep = find(i);
                            
            int tt = a[i].num;
                            a[i].num 
            -= tt;
                            a[tep].num 
            += tt;
                    }
                    
            for(i = 0;i < n; i++)
                            
            if(a[i].num != 0){
                                    flag 
            = true;
                                    
            break;
                            }
                    
            if(flag) printf("IMPOSSIBLE\n");
                    
            else     printf("POSSIBLE\n");
            }

            Code 2:

            #include <cstdio>
            #include 
            <cstring>
            struct Node{
                    
            int father,v,num;
            }a[
            10002];
            int find(int n){
                    
            int m = n,tep;
                    
            while(n != a[n].father)
                            n 
            = a[n].father;
                    
            while(m != n){
                            tep 
            = a[m].father;
                            
            int tt = a[m].num;
                            a[m].num 
            -= tt;
                            a[tep].num 
            += tt;
                            a[m].father 
            = n;
                            m 
            = tep;
                    }
                    
            return n;
            }
            void Union(int root1,int root2){
                    
            int t1,t2;
                    t1 
            = find(root1),t2 = find(root2);
                    
            if(t1 == t2) return ;
                    
            else{
                            
            if(a[t1].v > a[t2].v){
                                    a[t1].v 
            += a[t2].v;
                                    a[t2].father 
            = t1;
                            }
                            
            else{
                                    a[t2].v 
            += a[t1].v;
                                    a[t1].father 
            = t2;
                            }
                    }
            }
            int main()
            {
                    
            int n,m,i,j;
                    
            bool flag = false;
                    scanf(
            "%d%d",&n,&m);
                    
            for(i = 0;i < n; ++i){
                            a[i].father 
            = i,a[i].v = 0;
                            scanf(
            "%d",&a[i].num);
                    }
                    
            while(m--){
                            scanf(
            "%d%d",&i,&j);
                            Union(i,j);
                    }
                    
            for(i = 0;i < n; ++i)
                         
            if(a[i].num != 0) find(i);
                    
            for(i = 0;i < n; i++)
                            
            if(a[i].num != 0){
                                    flag 
            = true;
                                    
            break;
                            }
                    
            if(flag) printf("IMPOSSIBLE\n");
                    
            else     printf("POSSIBLE\n");
            }








            posted @ 2010-07-05 21:08 M.J 閱讀(307) | 評論 (0)編輯 收藏

            TOJ 1688. Corporative Network 并查集

                   這道題題意很難懂,大意是有N個(gè)公司,每個(gè)公司有一個(gè)center,最初每個(gè)公司的center都在自己公司,然后有M次操作,每次操作 A , B (A保證是一個(gè)集合的center,B不一定) 表示將A所在的集合并到B所在的集合,且B的center成為了A的center。每次操作后兩個(gè)公司的線的距離增加abs(A-B)%1000;
            Sample Input: (E  P表示查詢P距離自己center的線的長度,I   P  Q 表示合并 P ,Q);
            1
            4
            E 3
            I 3 1
            E 3
            I 1 2
            E 3
            I 2 4
            E 3
            O
            Sample Output:
            0
            2
            3
            5

            Code:
            #include <cstdio>
            #include 
            <iostream>
            #define M 20010
            using namespace std;

            struct Node{
                    
            int father,num;
            }a[M];
            void initial(int n){
                    
            int i;
                    
            for(i = 1;i <= n; i++){
                            a[i].father 
            = i;
                            a[i].num 
            = 0;
                    }
            }
            int find(int n){
                    
            int tep,m = n;
                    
            if(n == a[n].father) return n;
                    find(a[n].father);               
            //遞歸查找n的祖先
                    a[n].num += a[a[n].father].num;   //n的直需要更新(加上n的父親的值)
                    a[n].father = a[a[n].father].father;
            }
            int main()
            {
                    
            int T,n,i,j,k;
                    
            char order[3];
                    scanf(
            "%d",&T);
                    
            while(T--){
                            scanf(
            "%d",&n);
                            initial(n);
                            
            while(scanf("%s",order)){
                                    
            if(order[0]== 'O'break;
                                    
            if(order[0== 'E'){
                                            scanf(
            "%d",&k);
                                            find(k);
                                            printf(
            "%d\n",a[k].num);
                                    }
                                    
            else{
                                            scanf(
            "%d%d",&j,&k);
                                            
            int dis = abs(j-k)%1000;
                                            a[j].num 
            = dis;           //該值dis為j的值
                                            a[j].father = k;          //k成為了j的父親
                                    }
                            }
                    }
            }





            posted @ 2010-07-05 20:48 M.J 閱讀(141) | 評論 (0)編輯 收藏

            TOJ 2904【JAVA大數(shù)的進(jìn)制問題】

            題目給定一個(gè)進(jìn)制b,然后給兩個(gè)b進(jìn)制下的大數(shù) m 和 n ,要求求出m % n的結(jié)果,用b進(jìn)制表示。
            最近在學(xué)JAVA,發(fā)現(xiàn)做起高精度簡直太爽了~ 這個(gè)題有JAVA簡直就是個(gè)水題,知道一些函數(shù)就好了。
            BigInteger a = in.nextBigInteger(base);       //將一個(gè)大數(shù)按照base進(jìn)制輸入
            a.mod(b) ;                                                 //a%b,其中a和b都是大數(shù)且結(jié)果為10進(jìn)制,不管a和b是什么進(jìn)制
            String str= a.toString(base);                      //將一個(gè)大數(shù)a轉(zhuǎn)換成b進(jìn)制的字符串

            這個(gè)題就用到這些東西,代碼就不貼了。~~

            posted @ 2010-06-23 16:05 M.J 閱讀(236) | 評論 (0)編輯 收藏

            TOJ 1135 Matrix Chain Multiplication

            很簡單的題,給定N個(gè)矩陣,然后給出一系列運(yùn)算式,用括號來限制運(yùn)算,最后求一共進(jìn)行了多少次乘法運(yùn)算。
            R(m,s) 和Q(s,n)相乘,要進(jìn)行m*s*n次~
            處理運(yùn)算先后的時(shí)候,用棧實(shí)現(xiàn),即后進(jìn)先出就可以了。
            Sample Input:
            9
            A 50 10
            B 10 20
            C 20 5
            D 30 35
            E 35 15
            F 15 5
            G 5 10
            H 10 20
            I 20 25
            A
            B
            C
            (AA)
            (AB)
            (AC)
            (A(BC))
            ((AB)C)
            (((((DE)F)G)H)I)
            (D(E(F(G(HI)))))
            ((D(EF))((GH)I))
            Sample Outout:
            0
            0
            0
            error
            10000
            error
            3500
            15000
            40500
            47500
            15125
            Code:
            #include <iostream>
            #include 
            <cstdio>
            #include 
            <string>
            #include 
            <map>
            using namespace std;

            struct Matrx{
                    
            char id;
                    
            int x,y;
            }a[
            30];
            Matrx stack[
            100];
            int main()
            {
                    
            int i,j,k,n,ans;
                    
            bool flag;
                    map
            <char,int>mark;
                    scanf(
            "%d",&n);
                    
            for(i = 1;i <= n; i++){
                            cin 
            >> a[i].id;
                            scanf(
            "%d%d",&a[i].x,&a[i].y);
                            mark[a[i].id] 
            = i;
                    }
                    
            string str;
                    
            while(cin>>str){
                            ans 
            = 0; flag = true;
                            
            int len = str.length();
                            
            int head,tail;
                            head 
            = tail = 0;
                            
            for(i = 0;i <len; i++){
                                    
            if(str[i] == '(')
                                            
            continue;
                                    
            else if(str[i] == ')'){     //pop
                                            if(head == 1)
                                                    head 
            --;
                                            
            else if(head > 1){
                                                    
            int tx = stack[head-2].x;
                                                    
            int ty = stack[head-1].y;
                                                    
            if(stack[head-2].y != stack[head-1].x) flag = false;
                                                    ans 
            += stack[head-2].x*stack[head-2].y*stack[head-1].y;
                                                    head 
            -= 2;
                                                    stack[head].x 
            = tx;
                                                    stack[head
            ++].y = ty;
                                            }

                                    }
                                    
            else{        // push
                                            stack[head++= a[mark[str[i]]];

                                    }
                            }
                            
            if(!flag) printf("error\n");
                            
            else printf("%d\n",ans);
                    }
            }




            posted @ 2010-06-12 22:10 M.J 閱讀(177) | 評論 (0)編輯 收藏

            【DP】TOJ 2820 How many different ways

            給定從1 到 N的 N 個(gè)數(shù),問有多少種不同方案劃分這些數(shù)。比如N = 3,則有5種方案:
            {{1},{2},{3}}
            {{1,2},{3}}
            {{1,3},{2}}
            {{2,3},{1}}
            {{1,2,3}}
            最后的結(jié)果只保留后四位,即mod10000;
            上網(wǎng)查了下,集合的劃分的個(gè)數(shù)叫做bell數(shù),bell數(shù)可以遞歸求解:
            bell[0] = 1;
            bell [n + 1] = sigma(C(n,k))*(bell[k]); (0<=k<=n)

             
            然而這個(gè)題卻不可以這樣做,因?yàn)镹得范圍是2000,這樣做必定超時(shí),于是想到了DP,如果用dp[i][j]表示i個(gè)數(shù)
            劃分成j個(gè)集合,那么便有dp[i][j] = j * dp[i-1][j] + dp[i-1][j-1];( i > j )直觀理解就是,將i個(gè)數(shù)劃分成j個(gè)集合的個(gè)數(shù),即為i-1個(gè)數(shù)劃分到j(luò)個(gè)集合的數(shù),再將多的那個(gè)依次放到j(luò)個(gè)集合中,所以乘以j,或者是i-1個(gè)數(shù)放在j-1個(gè)集合中,第j個(gè)集合為空,則正好將多的這個(gè)數(shù)放到這個(gè)集合中,于是便有上邊的狀態(tài)轉(zhuǎn)移方程。
            Code:

             

            #include <cstdio>
            #include 
            <iostream>
            #include 
            <cmath>
            using namespace std;

            int map[2002][2002];
            void DP(){
                memset(map,
            0,sizeof(map));
                
            int i,j,k;
                
            for(i = 0;i <= 2000; i++){
                    map[i][i] 
            = 1;
                    map[i][
            1= 1;
                }

                
            for(i = 0;i <= 2000 ;i++)
                    
            for(j = 0; j < i; j++)
                        map[i][j] 
            = (j * map[i-1][j] + map[i-1][j-1])%10000;
            }

            int main()
            {
                
            int i,j,k,n;
                DP();
                
            while(scanf("%d",&n),n){
                    
            int ans = 0;
                    
            for(i = 0;i <= n; i++)
                        ans 
            = (ans + map[n][i])%10000;
                    
            string str = "0000";
                    str[
            3= ans%10+'0'; ans/=10;
                    str[
            2= ans%10+'0'; ans/=10;
                    str[
            1= ans%10+'0'; ans/=10;
                    str[
            0= ans%10+'0'; ans/=10;
                    cout
            <<str<<endl;
                }

            }

            posted @ 2010-06-12 15:05 M.J 閱讀(312) | 評論 (0)編輯 收藏

            Dilworth定理及相關(guān)題目

            偏序集的兩個(gè)定理:
            定理1) 令(X,≤)是一個(gè)有限偏序集,并令r是其最大鏈的大小。則X可以被劃分成r個(gè)但不能再少的反鏈。
            其對偶定理稱為Dilworth定理:
            定理2) 令(X,≤)是一個(gè)有限偏序集,并令m是反鏈的最大的大小。則X可以被劃分成m個(gè)但不能再少的鏈。
             即:鏈的最少劃分?jǐn)?shù)=反鏈的最長長度
            相關(guān)的題目有pku 1065,pku 3636,pku 1548
            POJ 3636:
            #include<iostream>
            #include
            <algorithm>
            #define M 20002
            using namespace std;
            struct Node{
                
            int h,w;
            }
            a[M];
            int tail[M],n;
            void LIS(int n){
                
            int i,j,m,len,mid,low,high;
                len
            =1;tail[1]=a[1].h;
                
            for(i=2;i<=n;i++){
                    
            if(tail[len]<=a[i].h) {
                        len
            ++;
                        tail[len]
            =a[i].h;
                    }

                    
            else{
                        low
            =1;high=len; 
                        
            while(low<high){
                            mid
            =(low+high)/2;
                            
            if(a[i].h>=tail[mid]) low=mid+1;
                            
            else high=mid;
                        }

                        tail[low]
            =a[i].h;
                    }

                }
                                
                printf(
            "%d\n",len);      
            }

            bool cmp(Node a,Node b){
                
            if(a.w!=b.w)return a.w>b.w;
                
            else return a.h<b.h;
            }

            int main()
            {
                
            int i,j,k,cas;
                scanf(
            "%d",&cas);    
                
            while(cas--){
                    scanf(
            "%d",&n);
                    
            for(i=1;i<=n;i++)
                        scanf(
            "%d%d",&a[i].w,&a[i].h);
                    sort(a
            +1,a+1+n,cmp);
                    LIS(n);
                }

                
            //system("pause");
                return 0;
            }
            POJ  1548:
            #include<iostream>
            #include
            <algorithm>
            using namespace std;
            int k,a[700],tail[800],b[860];
            void LIS(){
                
            int i,j,m,n,len,mid,left,right;
                n
            =1;
                
            for(i=k-1;i>=1;i--) b[n++]=a[i];
                n
            --;
                len
            =1;tail[1]=b[1];
                
            for(i=2;i<=n;++i){
                    
            if(b[i]>tail[len]){
                        len
            ++;
                        tail[len]
            =b[i];
                    }

                    
            else{
                        left
            =1;right=len;
                        
            while(left<right){              //二分查找插入的位置 
                            mid=(left+right)/2;
                            
            if(tail[mid]<b[i]) left=mid+1;
                                
            else  right=mid;
                            }

                        tail[left]
            =b[i];                //插入 
                    }
             
                }
                                
                printf(
            "%d\n",len);      
            }

            int main()
            {
                
            int i,j,m,n;
                
            while(1){
                    k
            =1;
                    scanf(
            "%d%d",&i,&j);
                    
            if(i==-1&&j==-1break;
                    a[k
            ++]=j;
                    
            while(scanf("%d%d",&i,&j)){
                        
            if(i==0&&j==0 ){
                            LIS();
                            
            break;        
                        }

                        a[k
            ++]=j;
                    }
                
                }

            }

            posted @ 2010-05-28 18:35 M.J 閱讀(1079) | 評論 (0)編輯 收藏

            僅列出標(biāo)題
            共4頁: 1 2 3 4 
            亚洲欧美精品一区久久中文字幕| 久久精品国产精品亚洲下载 | 亚洲中文字幕无码久久2020| 亚洲级αV无码毛片久久精品| 伊人久久大香线蕉av一区| 久久天天躁狠狠躁夜夜躁2O2O| 丰满少妇高潮惨叫久久久| 久久久受www免费人成| 国产精品9999久久久久| 国产成人99久久亚洲综合精品| 无码8090精品久久一区| 亚洲午夜无码久久久久| 亚洲欧美精品伊人久久| 国产毛片欧美毛片久久久 | 丁香五月综合久久激情| 日韩久久无码免费毛片软件| 久久久久人妻一区精品色| 色婷婷狠狠久久综合五月| 国产精品久久久亚洲| 亚洲午夜无码AV毛片久久| 国产精品热久久毛片| 漂亮人妻被黑人久久精品| 亚洲国产高清精品线久久| 国产成人精品久久一区二区三区av | 久久亚洲国产成人精品性色| 久久亚洲欧洲国产综合| 伊人久久免费视频| 99久久精品免费看国产一区二区三区 | 精品久久久久久无码免费| 久久久久99精品成人片三人毛片| 亚洲乱码日产精品a级毛片久久 | 久久99国产精品久久99小说| 国产三级精品久久| 久久se精品一区二区| 国产精品久久久久久福利漫画| 伊人 久久 精品| 亚洲婷婷国产精品电影人久久| 久久久久国产精品麻豆AR影院| 久久中文娱乐网| 99久久国产亚洲高清观看2024 | 久久毛片免费看一区二区三区|