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

            QuXiao

            每天進步一點點!

              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
              50 隨筆 :: 0 文章 :: 27 評論 :: 0 Trackbacks

            #

            題目來源:

            PKU 1018 Communication System

             

            算法分類:

            枚舉+貪心

             

            原文:

            Communication System

            Time Limit:1000MS  Memory Limit:10000K

            Description

            We have received an order from Pizoor Communications Inc. for a special communication system. The system consists of several devices. For each device, we are free to choose from several manufacturers. Same devices from two manufacturers differ in their maximum bandwidths and prices.
            By overall bandwidth (B) we mean the minimum of the bandwidths of the chosen devices in the communication system and the total price (P) is the sum of the prices of all chosen devices. Our goal is to choose a manufacturer for each device to maximize B/P.

            Input

            The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by the input data for each test case. Each test case starts with a line containing a single integer n (1 ≤ n ≤ 100), the number of devices in the communication system, followed by n lines in the following format: the i-th line (1 ≤ i ≤ n) starts with mi (1 ≤ mi ≤ 100), the number of manufacturers for the i-th device, followed by mi pairs of positive integers in the same line, each indicating the bandwidth and the price of the device respectively, corresponding to a manufacturer.

            Output

            Your program should produce a single line for each test case containing a single number which is the maximum possible B/P for the test case. Round the numbers in the output to 3 digits after decimal point.

            Sample Input

            1 3

            3 100 25 150 35 80 25

            2 120 80 155 40

            2 100 100 120 110

             

            Sample Output

            0.649

             

            Source

            Tehran 2002, First Iran Nationwide Internet Programming Contest

             

             

            中文描述:

            你需要購買n種設備來組一個通信系統,每一種設備,又是由一些不同的制造商生產的,不同制造商生產的同種設備會有不同的帶寬和價格。現在你要在每一個設備的制造商中選一個,使得購買的n種設備,它們帶寬的最小值與價格之和的比最大。

             

            題目分析:

            一開始想到的就是暴搜,但是搜索的深度達到100,時間肯定是不允許的。想要解決這題,必須找到一個好的查找策略。再想想看這題的特點,最后的答案,帶寬是選取所有設備中的最小值,而價格是選取所有設備的價格總和。如果某個制造商生產的某種設備,它的帶寬較高而價格較低,那么選取它的可能性就比較大。再進一步說,如果所選取的n種設備的帶寬的最小值b已經確定,那么對于某種設備,我們就可以在那些生產這種設備的,帶寬大于等于b的制造商中進行選擇。當然是選那個價格最低的設備,因為答案的分子已經確定為b,所以分母越小越好。看來只要枚舉b,再對于每個設備貪心的選擇最小價格就可以了,時間復雜度為OmnB),B為帶寬枚舉的數量。但問題又來了,應該怎么枚舉帶寬,題目中并未給出帶寬的取值范圍,如果從0..maxB一個一個枚舉的話,既費時又會造成過多重復情況(如果枚舉那些在輸入中出現的兩個連續帶寬之間的值,最后的答案是一樣的)。所以我們應該采取某個方法記錄輸入中出現過的帶寬(STL中的set是個不錯的選擇),再枚舉這些帶寬。在枚舉中,可能出現這種情況:枚舉b,選擇了n種設備,但選擇的所有設備的帶寬都大于b,那么最終用b/price就不是這種情況的正確答案。其實不用擔心,因為正確答案一定大于b/price。假設上面這種情況的實際帶寬最小值是b’,那個當我們再去枚舉b’時,至少有一個設備的帶寬等于b’,這次得到的答案也就是上面那種情況的答案,所以最終還是能得到正確解。

             

            代碼:

            #include <iostream>

            #include <map>

            #include <set>

            #include <climits>

            using namespace std;

             

            const int MAX = 105;

             

            struct Info

            {

                            int band, price;

            };

             

            struct Device

            {

                            int manuNum;

                            Info info[MAX];

                            map<int, int> minPrice;                 //map[i] = j 表示帶寬>=i的最小價格是j

                            int minBand, maxBand;

            };

             

            Device device[MAX];

            int deviceNum;

            set<int> band;                                                                  //輸入中出現過的band

            set<int>::iterator start, end;

            int maxBand, minBand;                                 //需要枚舉的band的最值

             

            int cmp( const void *a , const void *b )

            {

                            Info *c = (Info *)a;

                            Info *d = (Info *)b;

                            if(c->band != d->band)

                                            return d->band - c->band;

                            else

                                            return c->price - d->price;

            }

             

            void Input ()

            {

                            int i, j, max, min;

                            band.clear();

                            cin>>deviceNum;

                            for (i=0; i<deviceNum; i++)

                            {

                                            device[i].minBand = INT_MAX;

                                            device[i].maxBand = -1;

                                            cin>>device[i].manuNum;

                                            for (j=0; j<device[i].manuNum; j++)

                                            {

                                                            cin>>device[i].info[j].band>>device[i].info[j].price;

                                                            band.insert(device[i].info[j].band);

                                                            if ( device[i].info[j].band > device[i].maxBand )

                                                                            device[i].maxBand = device[i].info[j].band;

                                                            if ( device[i].info[j].band < device[i].minBand )

                                                                            device[i].minBand = device[i].info[j].band;

                                            }

                                                                           

                            }

            }

             

            void Pre ()                                           //預處理

            {

                            int i, j, min, b;

                            //計算所需枚舉的帶寬的最值

                            maxBand = INT_MAX;                   //maxBand為所有設備帶寬最大值的最小值

                            minBand = INT_MAX;                    //minBand為所有設備帶寬最小值的最小值

                            for (i=0; i<deviceNum; i++)

                            {

                                            if ( device[i].maxBand < maxBand )

                                                            maxBand = device[i].maxBand;

                                            if ( device[i].minBand < minBand )

                                                            minBand = device[i].minBand;

                            }

             

                            //對于每個設備,找到帶寬大于等于某一值的最小價格

                            for (i=0; i<deviceNum; i++)

                            {

                                            //band從大到小,band相等時price從小到大

                                            qsort(device[i].info, device[i].manuNum, sizeof(Info), cmp);

                                            device[i].minPrice.clear();

                                            min = device[i].info[0].price;

                                            b = device[i].info[0].band;

                                            device[i].minPrice[b] = min;

                                            for (j=1; j<device[i].manuNum; j++)

                                            {

                                                            if ( device[i].info[j].band == b )

                                                                            continue;

                                                            if ( device[i].info[j].price < min )

                                                            {

                                                                            min = device[i].info[j].price;

                                                            }

                                                            b = device[i].info[j].band;

                                                            device[i].minPrice[b] = min;

                                            }

                            }             

            }

             

            void Solve ()

            {

                            Pre();

             

                            int b, i, totalPrice;

                            double rate, ans;

                            map<int, int>::iterator it;

                            ans = 0;

                            start = band.find(minBand);

                            end = band.find(maxBand);

                            end ++;

                            while ( start != end )

                            {

                                            b = *start;

                                            start ++;

                                            totalPrice = 0;

                                            for (i=0; i<deviceNum; i++)

                                            {

                                                            //找到帶寬大于等于b的最小價格

                                                            for (it=device[i].minPrice.begin(); it!=device[i].minPrice.end(); it++)

                                                            {

                                                                            if ( it->first >= b )

                                                                            {

                                                                                            totalPrice += it->second;

                                                                                            break;

                                                                            }

                                                            }

             

                                            }

                                            rate = double(b) / totalPrice;

                                            if ( rate > ans )

                                                            ans = rate;

                            }

             

                            printf("%.3f\n", ans);

            }

             

            int main ()

            {

                            int test;

                            cin>>test;

                            while ( test -- )

                            {

                                            Input ();

                                            Solve ();

                            }

             

                            return 0;

            }

            posted @ 2008-04-25 21:25 quxiao 閱讀(1519) | 評論 (6)編輯 收藏

                 摘要: 解題報告   題目來源: PKU 3513 Let's Go to the Movies   分類: 樹形DP   原文: Let's Go to the Movies   Time Limit: 1000MS ...  閱讀全文
            posted @ 2008-03-25 23:16 quxiao 閱讀(556) | 評論 (0)編輯 收藏

            解題報告

             

            題目來源:

            PKU 1505 Copying Books

             

            算法分類:

            DP

             

            原文:

            Copying Books

            Time Limit: 3000MS


            Memory Limit: 10000K

            Total Submissions: 1806


            Accepted: 404

            Description

            Before the invention of book-printing, it was very hard to make a copy of a book. All the contents had to be re-written by hand by so called scribers. The scriber had been given a book and after several months he finished its copy. One of the most famous scribers lived in the 15th century and his name was Xaverius Endricus Remius Ontius Xendrianus (Xerox). Anyway, the work was very annoying and boring. And the only way to speed it up was to hire more scribers.

            Once upon a time, there was a theater ensemble that wanted to play famous Antique Tragedies. The scripts of these plays were divided into many books and actors needed more copies of them, of course. So they hired many scribers to make copies of these books. Imagine you have m books (numbered 1, 2 ... m) that may have different number of pages (p1, p2 ... pm) and you want to make one copy of each of them. Your task is to divide these books among k scribes, k <= m. Each book can be assigned to a single scriber only, and every scriber must get a continuous sequence of books. That means, there exists an increasing succession of numbers 0 = b0 < b1 < b2, ... < bk-1 <= bk = m such that i-th scriber gets a sequence of books with numbers between bi-1+1 and bi. The time needed to make a copy of all the books is determined by the scriber who was assigned the most work. Therefore, our goal is to minimize the maximum number of pages assigned to a single scriber. Your task is to find the optimal assignment.

            Input

            The input consists of N cases. The first line of the input contains only positive integer N. Then follow the cases. Each case consists of exactly two lines. At the first line, there are two integers m and k, 1 <= k <= m <= 500. At the second line, there are integers p1, p2, ... pm separated by spaces. All these values are positive and less than 10000000.

            Output

            For each case, print exactly one line. The line must contain the input succession p1, p2, ... pm divided into exactly k parts such that the maximum sum of a single part should be as small as possible. Use the slash character ('/') to separate the parts. There must be exactly one space character between any two successive numbers and between the number and the slash.

            If there is more than one solution, print the one that minimizes the work assigned to the first scriber, then to the second scriber etc. But each scriber must be assigned at least one book.

            Sample Input

            2

            9 3

            100 200 300 400 500 600 700 800 900

            5 4

            100 100 100 100 100

            Sample Output

            100 200 300 400 500 / 600 700 / 800 900

            100 / 100 / 100 / 100 100

            Source

            Central Europe 1998

             

             

            中文描述:

            題目大意是給你m1…m)本書,每本書有Pm頁,用kk<=m)個員工來復印這些書。每本書只能分配給一個員工來復印,并且每個員工必須復印一段連續的書籍,每個員工復印的時間取決于所復印書籍的總頁數。讓你給出相應的分配,使得分配給員工的書籍頁數的最大值盡量小。注意,如果有多種分配的方案,使得第一個員工的書籍頁數盡量少,其次是第二個、第三個……以此類推。

             

            題目分析:

            我們可以從后往前推,最后一個員工,也就是第k個員工,他至少要復印第m本書,至多可以復印第k本到第m本(因為至少要分配給前k-1個員工每人一本書)。假設,第k名員工復制第ik<=i<=m)本書到第m本書,那么,所有員工復印書籍的最小時間就為第k名員工所需的時間以及前k-1名員工復制前i-1本書所需最小時間的較大的那個時間。這樣,問題的規模就從k個員工復印m本書減小到了k-1個員工復印i-1本書,而且求解過程中會不斷遇到前a個員工復印前b本書的最小時間。為了減小問題的規模以及記錄重復子問題的解,就可以用DP。

            但僅僅算出最小時間的不夠的,還要給出分配的方案,這個稍微有點繁瑣。因為題目中說,如果有多種最優的分配方案,應該讓前面的員工分配的頁數盡量少。那么,可以從后推,在當前的員工所復印的書籍頁數沒有超過最大頁數的情況下,讓其復印的頁數最大化。如果超過了最大頁數,就把這本書分配給前一名員工。最后再按順序將分配結果輸出出來。

             

            代碼:

            #include <cstdio>

            #include <climits>

            #include <cstring>

             

            const int MAX = 505;

            int book[MAX];

            __int64 total[MAX];                        //1~n本書的頁數

            int k, m;

            __int64 f[MAX][MAX];                  //f[i][j] = k 表示前i個人復制前j本書所需最少時間是k

            __int64 max;

            void Input ()

            {

                            scanf("%d%d", &m, &k);

                            int i;

                            for (i=1; i<=m; i++)

                                            scanf("%d", &book[i]);

            }

             

            __int64 Sum (int s, int e)                                               //s本書到第e本書的總頁數

            {

                            return (total[e] - total[s-1]);

            }

             

            __int64 Max (__int64 a, __int64 b)

            {

                            return ( a>b?a:b );

            }

             

            __int64 Min (int x, int y)                                //x個人復制前y本書所需的最少時間        x<=y

            {

            //考慮特殊情況

                            if ( f[x][y] != -1 )

                                            return f[x][y];

                            if ( y == 0 )

                                            return ( f[x][y] = 0 );

                            if ( x == 0 )

                                            return ( f[x][y] = INT_MAX );

             

                            int i;

                            __int64 temp;

                            f[x][y] = INT_MAX;

                            for (i=x-1; i<y; i++)

                            {

            //x個人復制第i+1到第y本書與前x-1個人復制前i本書的時間較大的時間

                                            temp = Max( Min(x-1, i), Sum(i+1, y) );                 

                                            if ( temp < f[x][y] )

                                            {

                                                            f[x][y] = temp;

                                            }

                            }

                            return f[x][y];

            }

             

            void Output ()

            {

                            int i, p;

                            __int64 temp;

                            int slash[MAX];

                            max = f[k][m];

                            memset(slash, 0, sizeof(slash));

                            temp = 0;

                            p = k;

                            for (i=m; i>0; i--)

                            {

                                            //讓后面的員工盡量復印最多的書籍

                                            if ( temp + book[i] > max || i < p )

                                            {

                                                            slash[i] = 1;

                                                            temp = book[i];

                                                            p --;

                                            }

                                            else

                                            {

                                                            temp += book[i];

                                            }

                            }

             

                            for (i=1; i<=m; i++)

                            {

                                            printf("%d", book[i]);

                                            if ( slash[i] == 1 )

                                                            printf(" / ");

                                            else if ( i != m )

                                                            printf(" ");

                            }

                            printf("\n");

            }

             

            void Solve ()

            {

                            int i, j;

                            //預處理書籍頁數的和

                            total[0] = 0;

                            for (i=1; i<=m; i++)

                                            total[i] = total[i-1] + book[i];

             

                            memset(f, -1, sizeof(f));

                           

                            Min(k, m);

                           

                            Output();

            }

             

            int main ()

            {

                            int test;

                            scanf("%d", &test);

                            while ( test-- )

                            {

                                            Input ();

                                            Solve ();

                            }

             

                            return 0;

            }

             

             

            程序分析與心得:

            時間復雜度O(n2),空間復雜度O(n2)

            在用記憶化搜索解決DP問題時,往往比較符合人的思維,容易想到模型,編程比較簡單。在解題過程中,除了可以按照常理順著推,也可以嘗試逆向思維,從最后的狀態倒著推,這樣可以使問題想得更加透徹,有比較好的效果。

            posted @ 2008-03-10 15:11 quxiao 閱讀(551) | 評論 (0)編輯 收藏

            題目大意:
                給你n個藥的序列,牛從時間1開始吃藥,在奇數時間吃藥可以增加彈跳力,在偶數時間吃藥則會減少彈跳力。在某一時間,你可以跳過一些藥,但一旦吃過某種藥,你就不能在選前面的藥了。問你某一個吃藥的序列,使牛最終的彈跳力最大。

            思路:
                雖然題目不難,但思考題目的過程十分有意思。對于某種藥,共有4中狀態:在奇數時間吃、在奇數時間不吃、在偶數時間吃以及在偶數時間不吃。關鍵在于這4種狀態之間的轉移。因為如果跳過某種藥是不需要花費時間的,所以在某2次的吃藥時間內,時間相當于是靜止的,一直維持在第1次吃藥的時間段內。
                所以可用一數組max[i][2][2]表示狀態,第i種藥在奇/偶時間段內吃/不吃??傻脿顟B轉移可表示為:
                max[i][0][0] = Max (max[i-1][0][0], max[i-1][0][1]);
                max[i][0][1] = Max (max[i-1][1][0], max[i-1][1][1]) - high[i];
                max[i][1][0] = Max (max[i-1][1][0], max[i-1][1][1]);
                max[i][1][1] = Max (max[i-1][0][0], max[i-1][0][1]) + high[i];

            代碼:

            #include <iostream>
            using namespace std;

            const int MAX = 150005;
            int high[MAX];
            int max[MAX][2][2];
            int n;

            void Input ()
            {
                scanf("%d", &n);
                int i;
                for (i=1; i<=n; i++)
                    scanf("%d", &high[i]);

            }

            int Max (int a, int b)
            {
                return ( a>b?a:b );
            }

            void Solve ()
            {
                int i;
                for (i=1; i<=n; i++)
                {
                    max[i][0][0] = Max (max[i-1][0][0], max[i-1][0][1]);
                    max[i][0][1] = Max (max[i-1][1][0], max[i-1][1][1]) - high[i];
                    max[i][1][0] = Max (max[i-1][1][0], max[i-1][1][1]);
                    max[i][1][1] = Max (max[i-1][0][0], max[i-1][0][1]) + high[i];
                }
                printf("%d\n", Max ( Max(max[n][0][0], max[n][0][1]), Max(max[n][1][0], max[n][1][1])) );
            }

            int main ()
            {
                Input ();
                Solve ();

                return 0;
            }
            posted @ 2008-02-02 21:41 quxiao 閱讀(937) | 評論 (0)編輯 收藏

            題目大意:
                給定n個連續的長度為1的矩形的高度h(1<=n<=100000,0<=hi<=1000000000),問你其中能構成的最大矩形的面積是多少。

            思路:
                很顯然,用DP。但關鍵是怎樣表示狀態,一開始想用一個二維數組min[][]表示從i~j的最小高度,面積就等于min[i][j]*(j-i+1)。但很不幸,根據題目給定的n的范圍,這個二維數組根本無法創建。:(
                后來從論壇上得到提示,因為對于圖中的某個面積最大的矩形,必然有一個最低的高度h[k],即矩形的高等于h[k],以第k塊矩形的高度,最左邊可以到達這個矩形的左邊,最右邊可以到達這個矩形的右邊。所以,可以以每塊矩形進行擴展,求出最左邊和最右邊(即兩邊的高度都大于等于這塊的高度),得出面積s[i],這樣就可求出最大的s[i]了。

            代碼:

            #include <cstdio>

            const int MAX = 100005;
            __int64 h[MAX];
            __int64 left[MAX], right[MAX];        //left[i] = j表示第i個矩形以它的高度到達最左邊的下標
            int n;

            bool Input ()
            {
                scanf("%d", &n);
                if ( n == 0 )
                    return false;
                int i;
                for (i=1; i<=n; i++)
                    scanf("%I64d", &h[i]);
                h[0] = h[n+1] = -1;
                return true;
            }

            void Solve ()
            {
                int i;
                __int64 temp, max;
                for (i=1; i<=n; i++)
                {
                    left[i] = right[i] = i;
                }

                for (i=1; i<=n; i++)
                {
                    while ( h[left[i]-1] >= h[i] )
                        left[i] = left[left[i]-1];
                }
                for (i=n; i>0; i--)
                {
                    while ( h[right[i]+1] >= h[i] )
                        right[i] = right[right[i]+1];
                }

                max = 0;
                for (i=1; i<=n; i++)
                {
                    temp = h[i] * (right[i] - left[i] + 1);
                    if ( temp > max )
                        max = temp;
                }

                printf("%I64d\n", max);
            }

            int main ()
            {
                while ( Input() )
                {
                    Solve();
                }

                return 0;
            }


            posted @ 2008-02-01 19:34 quxiao 閱讀(1834) | 評論 (0)編輯 收藏

            題目大意:

                給定一個時間期間n,電腦的價格c,以及電腦的維修費用m(y,z)(第y臺電腦從y年用到第z年總的維修費用)。讓你求出在期限n中使用電腦的最低費用。

            思路:
                為了讓總費用最低,你必須作出這樣的決策:假設你正在使用某一臺電腦已用到y年,你y+1年是繼續用這臺電腦,還是重新買第y+1臺電腦(注意,這里的y+1是指輸入中的第y+1行電腦,而不是指你已購買了y+1臺電腦,因為y年只能買輸入中的第y行電腦,為了不產生混淆,將電腦用編號表示)。顯然,某一階段的最優解并不能一定導致全局的最優解,所以肯定不能用貪心。
                我們從最后的情況來考慮,最后必然是某一個編號為y的電腦,從第y年使用到第n年,而前面的1~y-1年,自己只可能購買編號為1~y-1的電腦使用到y-1年。這樣,問題的范圍就減小了,從編號為1~n的電腦使用n年,降低到了編號為1~y-1的電腦使用y-1年。經分析,可推出遞推式:
                F[n] = min { F[i] + c + m[i+1][n] | 0<=i<=n-1 }
            F[n]表示n臺電腦使用n年的最低費用

            代碼:

            #include <cstdio>
            #include <climits>
            #include <cstring>

            const int MAX = 1005;
            int n, c;
            int mend[MAX][MAX];
            int f[MAX];
            int cost;

            bool Input ()
            {
                if ( scanf("%d", &c) == EOF )
                    return false;
                scanf("%d", &n);
                int i, j;
                for (i=1; i<=n; i++)
                {
                    for (j=i; j<=n; j++)
                        scanf("%d", &mend[i][j]);
                }
                return true;
            }


            void Solve ()
            {
                int i, j;
                memset(f, 0, sizeof(f));
                for (i=1; i<=n; i++)
                {
                    f[i] = INT_MAX;
                    for (j=0; j<i; j++)
                    {
                        if ( f[j] + mend[j+1][i] + c < f[i] )
                            f[i] = f[j] + mend[j+1][i] + c;
                    }
                }
                printf("%d\n", f[n]);
            }

            int main ()
            {
                while ( Input() )
                {
                    Solve ();
                }

                return 0;
            }
            posted @ 2008-01-28 14:45 quxiao 閱讀(471) | 評論 (0)編輯 收藏

            題意:
                就是有這樣一個序列:1 12 123 1234 12345 .....,輸入序列的下標,讓你算出該序列所在下標的字符

            思路:
                一開始想用字符串模擬來做,結果TLE。后來看了discuss,又想了一下,發現可以按規律將序列分成幾段,然后再在每段中查找。具體做法是:先按序列 中數字的位數來分,112123...123456789是一段,1..10 1..11 1..12 ... 1..99是一段,1..100 ... 1..999是一段,以此類推。確定了是在上面的哪一段以后,再按類似的思想確定這個下標是在哪個12345...n的序列,最后判斷是在其中哪個數字的 哪一位。

            代碼:
            #include <iostream>
            #include <cmath>
            using namespace std;

            const long long a[] = {0, 45, 9045, 1395495, 189414495, 2147483648};            //112123...9, 11231234...99, ... 的位數
            const long long b[] = {1, 11, 192, 2893, 38894, 488895, 5888896};                //1, 1234...10, 1234...100, ...的位數

            int digit (int n)
            {
                int ans = 1;
                while ( n / 10 != 0 )
                {
                      n /= 10;
                      ans ++;
                }
                return ans;
            }

            char Pos (int n, long long index)      //在1234...n中找到下標為index的字符
            {
                 long long i, j;
                 long long pos = 0;
                 for (i=1; i<=n; i++)
                 {
                     pos += digit(i);
                     if ( pos >= index )
                        break;
                 }
                
                 pos -= digit(i);               //定位在i上
                 j = digit(i) - (index - pos);
                 //if ( j == digit(i) - 1 )
                 //   cout<<endl;
                 while ( j > 0 )
                 {
                       i /= 10;
                       j --;
                 }

                 return (i % 10) + '0';
            }


            char Find (long long pos)
            {
                 long long p, t;
                 int index = 0;
                 int temp;
                 while ( a[index] < pos )
                 {
                       index ++;
                 }
                 p = a[index - 1];
                
                 p += b[index - 1];
                 temp = int(pow(10.0, index-1));
                 t = b[index - 1] + index;
                 while ( p < pos )
                 {
                       p += t;
                       t += index;
                       temp ++;
                 }
                
                 p -= t - index;
                
                 return Pos(temp, pos-p);
            }

            int main ()
            {
                int test;
                long long i;
                cin>>test
                while ( test-- )
                {
                      cin>>i;
                      cout<<Find(i)<<endl;
                }

                return 0;
            posted @ 2008-01-19 16:46 quxiao 閱讀(1698) | 評論 (0)編輯 收藏

                一開始看還以為是一道博弈的題目,再仔細看才發現并不是博弈,也不是很難。大致意思是:有n堆石子,第i堆有Ki個石子,每輪一方可以從任意堆中取出一個或多個石子,所有石子都被取光時,游戲也結束了,那個最后一輪拿走石子的人就是勝利者。問你有多少種方法使對方處于必敗的局面。題目并不難,是因為題目中已經告訴你了產生必敗局面的條件:如果所有堆的石子數的異或和為0,那么處于此局面的人就必敗。
                因為每次只能從一個堆中取石子,所以只要對于每個堆i,先求出其他所有堆的異或和temp,再看0~Ki-1與這個異或和再進行異或是否為0,只要為0就得到一種勝利的方法。自己先是想枚舉0~Ki-1,與temp進行異或。后來感覺沒有必要,只要Ki>temp就可以了,因為若從堆i中取出x個石子,Ki-x異或temp==0 <==> Ki-x==temp,只要Ki>temp,就存在Ki-x==temp。

            #include <cstdio>

            #define PILE 1001

            __int64 stone[PILE], test;       //test為所有石子數的異或和
            int piles;

            bool Input ()
            {
                scanf("%d", &piles);
                if ( piles == 0 )
                    return false;
               
                int i;
                for (i=0; i<piles; i++)
                    scanf("%I64d", &stone[i]);
                return true;
            }

            void Solve ()
            {
                int i, ans;
                __int64 temp;
                test = 0;
                ans = 0;
                for (i=0; i<piles; i++)
                    test ^= stone[i];
               
                if ( test != 0 )
                {
                    for (i=0; i<piles; i++)
                    {
                        temp = test ^ stone[i];      //再與stone[i]做一次異或,相當于除stone[i]對其他所有堆的石子進行異或

                        if ( stone[i] > temp )
                            ans++;
                    }
                }
                printf("%d\n", ans);
            }

            int main ()
            {
                while ( Input() )
                {
                    Solve();
                }
               
                return 0;
            }


            posted @ 2007-12-07 21:41 quxiao 閱讀(713) | 評論 (4)編輯 收藏

                地圖上有一些beeper,讓你從起點搜集所有beeper,再回到起點。但你只可以水平或者豎直的走,不能走對角線。讓你找出這樣走的最短路徑長度。
                因為地圖最大只有20×20,而beeper最多也只有10個,所以可以考慮用深搜,找到所有可能路徑,在其中加一些簡單的減枝就可以了。起初以為會超時,可最后還是0ms。:)

            Source Code

            Problem: 2907
            User: QuXiao
            Memory: 176K
            Time: 0MS
            Language: C++
            Result: Accepted
            • Source Code
            • #include <iostream>
              #include <climits>
              using namespace std;

              struct Point
              {
              int x, y;
              };

              int num, X, Y;
              Point start, beeper[15];
              int shortest;
              int visited[15];


              int Length (Point p1, Point p2)
              {
              return abs(p1.x - p2.x) + abs(p1.y - p2.y);
              }

              void Input ()
              {
              int i;
              cin>>X>>Y;
              cin>>start.x>>start.y;
              cin>>num;
              for (i=0; i<num; i++)
              cin>>beeper[i].x>>beeper[i].y;
              }

              void DFS (int cur, int len, int n)
              {
              if ( n == num )
              {
              int t = Length(beeper[cur], start);
              if ( len + t < shortest )
              shortest = len + t;
              }
              else if ( len < shortest )
              {
              int i;
              for (i=0; i<num; i++)
              {
              if ( visited[i] == 0 )
              {
              visited[i] = 1;
              DFS (i, len+Length(beeper[cur], beeper[i]), n+1);
              visited[i] = 0;
              }
              }
              }
              }


              void Solve ()
              {
              int i, t;
              shortest = INT_MAX;
              memset(visited, 0, sizeof(visited));
              for (i=0; i<num; i++)
              {
              t = Length(beeper[i], start);
              visited[i] = 1;
              DFS (i, t, 1);
              visited[i] = 0;
              }
              cout<<"The shortest path has length "<<shortest<<endl;
              }

              int main ()
              {
              int test;
              cin>>test;
              while ( test-- )
              {
              Input ();
              Solve ();
              }

              return 0;
              }



            posted @ 2007-12-07 19:31 quxiao 閱讀(368) | 評論 (1)編輯 收藏

                大家好,我對算法比較感興趣。希望能借此平臺,與我有同樣愛好的朋友們能夠多多交流,共同進步!
            posted @ 2007-12-07 19:11 quxiao 閱讀(63) | 評論 (0)編輯 收藏

            僅列出標題
            共5頁: 1 2 3 4 5 
            久久精品国产精品亜洲毛片| 亚洲国产另类久久久精品小说 | 久久久久成人精品无码| 手机看片久久高清国产日韩| 亚洲色大成网站www久久九| 国产精品9999久久久久| 久久久受www免费人成| 久久午夜伦鲁片免费无码| 国产精品热久久无码av| 五月丁香综合激情六月久久| 久久久免费观成人影院| 久久国产亚洲高清观看| 亚洲七七久久精品中文国产| 久久国产精品久久精品国产| 一本一道久久综合狠狠老| 久久人人爽人人爽人人片AV麻豆 | 亚洲嫩草影院久久精品| 99久久精品国产一区二区| 婷婷久久综合九色综合98| 99久久无色码中文字幕人妻| 久久性精品| 99久久成人18免费网站| 97久久精品无码一区二区天美| 一本色道久久综合| 国产一区二区三精品久久久无广告| 色综合久久久久久久久五月 | 久久99国产亚洲高清观看首页| 99精品国产综合久久久久五月天| 婷婷久久综合| 欧美日韩中文字幕久久久不卡| 精品欧美一区二区三区久久久| 久久久久久久尹人综合网亚洲| 99精品国产在热久久| 69国产成人综合久久精品| 99久久人妻无码精品系列| 精品综合久久久久久97超人| 久久99国产精品尤物| 国产精品国色综合久久| 久久综合丝袜日本网| 99久久国产综合精品五月天喷水| 国产成人香蕉久久久久|