• <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>
            強(qiáng)烈推薦此題。圖論和DP結(jié)合。
            首先,我們分析一下分組的要求:
            1、把所有的人分成2組,每組至少有1人;
            2、每組之間的人兩兩認(rèn)識。
                非常明顯,如果存在兩個(gè)人A和B,A不認(rèn)識B,或B不認(rèn)識A,那么A和B一定不能分在同一組。因此,我們以人為結(jié)點(diǎn)重新構(gòu)造一個(gè)圖G。假如A和B不能分在同一組,那么就在G中增加一條無向邊(A,B)。這樣,我們就得到了一個(gè)較為“單純”的模型。下面我們對這個(gè)模型進(jìn)行簡單分析。
                我們先研究G的一個(gè)連通分量K1。對于這個(gè)連通分量,可以先求出K1的生成樹T1。對于K1中的任意結(jié)點(diǎn)a,假如a在T1中的深度為奇數(shù),我們就把a(bǔ)加入點(diǎn)集S1;否則我們把a(bǔ)加入點(diǎn)集S2(S1,S2最初為空集)。顯然最后S1,S2的交集為空。
                不難證明,如果存在不同結(jié)點(diǎn)p和q,p和q同屬于S1或S2,而且G中存在邊(p,q),那么要做到滿足題目要求的分組是不可能的,應(yīng)輸出No solution。否則,我們就得到了連通分量K1的唯一分組方案:分為S1,S2兩組。
                對于G中的每個(gè)連通分量Ki,我們可以求出相應(yīng)的S1i,S2i。最后,我們的目的是把全部人分為2組。也就是說,對于i=1,2,3,...,m,我們必須決定把S1i中的人分到第1組,S2i中的人分到第2組,還是做剛好相反的處理。由于題目要求最后兩組的總?cè)藬?shù)差最小,我們可以用動態(tài)規(guī)劃的辦法來確定究竟選取上面的哪種決策。
                不妨假設(shè)G中共有m個(gè)連通分量,記|S1i|=xi,|S2i|=yi(i=1,2,3,...,m)。若xi < yi,我們就交換xi和yi(這樣不影響結(jié)果的正確性)。記wi = xi - yi。那么只要對所有的wi做“半個(gè)背包”即可。也就是說,湊出盡量接近sum(wi)的數(shù)。接下去就非常簡單了。


            /*************************************************************************
            Author: WHU_GCC
            Created Time: 2007-8-29 12:07:38
            File Name: pku1112.cpp
            Description: 
            ***********************************************************************
            */

            #include 
            <iostream>
            #include 
            <vector>
            using namespace std;
            #define out(x) (cout << #x << ": " << x << endl)
            const int maxint = 0x7FFFFFFF;
            typedef 
            long long int64;
            const int64 maxint64 = 0x7FFFFFFFFFFFFFFFLL;
            template 
            <class T> void show(T a, int n) {for (int i = 0; i < n; ++i) cout << a[i] << ' '; cout << endl; }
            template 
            <class T> void show(T a, int r, int l) {for (int i = 0; i < r; ++i) show(a[i], l); cout << endl; }

            const int maxn = 110;

            int n;
            int g[maxn][maxn];

            int cnt_id;
            int id[maxn];
            int w[maxn];

            void dfs(int now, int new_id)
            {
                id[now] 
            = new_id;
                
            for (int i = 1; i <= n; i++if (id[i] == 0 && g[now][i])
                    dfs(i, new_id);
            }


            void make_id()
            {
                cnt_id 
            = 0;
                memset(id, 
            0sizeof(id));
                
            for (int i = 1; i <= n; i++if (id[i] == 0)
                    dfs(i, 
            ++cnt_id);
            }


            int set_mask[maxn];

            void divide(int cid, int now, int set_id, int *set_mask)
            {
                
            *(set_mask + now) = set_id;
                
            for (int i = 1; i <= n; i++if (*(set_mask + i) == 0 && id[i] == cid && g[now][i])
                    divide(cid, i, 
            3 - set_id, set_mask);
            }


            int ok()
            {
                memset(set_mask, 
            0sizeof(set_mask));
                
            for (int i = 1; i <= cnt_id; i++)
                
            {
                    
            for (int j = 1; j <= n; j++)
                        
            if (id[j] == i)
                        
            {
                            divide(i, j, 
            1, set_mask);
                            
            break;
                        }

                    
            int cntx = 0;
                    
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 1)
                        cntx
            ++;

                    
            int cnty = 0;
                    
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 2)
                        cnty
            ++;
                    
            if (cntx < cnty)
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i)
                            set_mask[j] 
            = 3 - set_mask[j];
                    }

                    
                    w[i] 
            = abs(cntx - cnty);
                    
                    
            int flag = 1;
                    
            for (int j = 1; j <= n && flag; j++if (id[j] == i && set_mask[j] == 1)
                        
            for (int k = 1; k <= n && flag; k++if (id[k] == i && set_mask[k] == 1 && j != k)
                            
            if (g[j][k]) flag = 0;
                    
            for (int j = 1; j <= n && flag; j++if (id[j] == i && set_mask[j] == 2)
                        
            for (int k = 1; k <= n && flag; k++if (id[k] == i && set_mask[k] == 2 && j != k)
                            
            if (g[j][k]) flag = 0;
                    
            if (flag == 0return 0;
                }

                
            return 1;
            }


            typedef 
            struct ptr_t
            {
                
            int ptr, value;
            }
            ;

            ptr_t pre[maxn];
            int mask[maxn];

            void print(int now)
            {
                
            if (pre[now].value == 0)
                    
            return;
                print(pre[now].ptr);
                mask[pre[now].value] 
            = 1;
            }


            void dp()
            {
                
            int f[maxn];

                memset(f, 
            0sizeof(f));
                memset(pre, 
            0sizeof(pre));
                f[
            0= 1;
                
            int sum = 0;
                
            for (int i = 1; i <= cnt_id; i++) sum += w[i];
                
            for (int i = 0; i <= cnt_id; i++)
                    
            for (int j = sum / 2; j >= 0; j--if (f[j] && !f[j + w[i]])
                    
            {
                        f[j 
            + w[i]] = 1;
                        pre[j 
            + w[i]].ptr = j;
                        pre[j 
            + w[i]].value = i;
                    }

                
            int ans_i;
                
            for (int i = sum / 2; i >= 0; i--if (f[i])
                
            {
                    ans_i 
            = i;
                    
            break;
                }

                memset(mask, 
            0sizeof(mask));
                print(ans_i);

                
            int cnt1 = 0;
                
            for (int i = 1; i <= cnt_id; i++)
                
            {
                    
            if (mask[i])
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 1)
                            cnt1
            ++;
                    }

                    
            else
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 2)
                            cnt1
            ++;
                    }

                }

                printf(
            "%d", cnt1);
                
            for (int i = 1; i <= cnt_id; i++)
                
            {
                    
            if (mask[i])
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 1)
                            printf(
            " %d", j);
                    }

                    
            else
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 2)
                            printf(
            " %d", j);
                    }

                }

                printf(
            "\n");
                
                
            int cnt2 = 0;
                
            for (int i = 1; i <= cnt_id; i++)
                
            {
                    
            if (mask[i])
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 2)
                            cnt2
            ++;
                    }

                    
            else
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 1)
                            cnt2
            ++;
                    }

                }

                printf(
            "%d", cnt2);
                
            for (int i = 1; i <= cnt_id; i++)
                
            {
                    
            if (mask[i])
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 2)
                            printf(
            " %d", j);
                    }

                    
            else
                    
            {
                        
            for (int j = 1; j <= n; j++if (id[j] == i && set_mask[j] == 1)
                            printf(
            " %d", j);
                    }

                }

                printf(
            "\n");
                
            }


            int main()
            {
                
            int tmp[maxn][maxn];
                
            while (scanf("%d"&n) != EOF)
                
            {
                    memset(tmp, 
            0sizeof(tmp));
                    
            for (int i = 1; i <= n; i++)
                    
            {
                        
            int t;
                        
            while (scanf("%d"&t), t != 0)
                            tmp[i][t] 
            = 1;
                    }

                    memset(g, 
            0sizeof(g));
                    
            for (int i = 1; i <= n; i++)
                        
            for (int j = 1; j <= n; j++)
                            
            if (i != j && (tmp[i][j] == 0 || tmp[j][i] == 0))
                                g[i][j] 
            = g[j][i] = 1;
                    make_id();
                    
            int t = ok();
                    
            if (!t)
                        printf(
            "No solution\n");
                    
            else
                        dp();
                }

                
            return 0;
            }
            posted on 2007-08-29 17:15 Felicia 閱讀(916) 評論(4)  編輯 收藏 引用 所屬分類: 動態(tài)規(guī)劃
            Comments
            • # re: [動態(tài)規(guī)劃]pku1112
              tmwli
              Posted @ 2007-09-17 16:24
              just this problem, hit, yesterday...
              do not know how to solve it.  回復(fù)  更多評論   
            • # re: [動態(tài)規(guī)劃]pku1112
              Felicia
              Posted @ 2007-09-17 16:27
              @tmwli
              你說的是昨天HIT的A題吧……
              那個(gè)題用匹配做的,題意和這個(gè)題不一樣
                回復(fù)  更多評論   
            • # re: [動態(tài)規(guī)劃]pku1112
              whl
              Posted @ 2009-05-20 14:10
              f[i] 含義是什么呀

                回復(fù)  更多評論   
            • # re: [動態(tài)規(guī)劃]pku1112
              whl
              Posted @ 2009-05-20 14:30
              dp() 這段代碼好難懂。 :(  回復(fù)  更多評論   
             
            久久精品国产黑森林| 久久综合九色综合精品| 久久精品人妻中文系列| 国产69精品久久久久观看软件| yy6080久久| 国产美女久久精品香蕉69| 国内精品伊人久久久久| 九九久久精品国产| 精品国产乱码久久久久久人妻 | 性做久久久久久久久浪潮| 久久精品国产99国产精品亚洲| 国产精品对白刺激久久久| 国产精品欧美久久久久无广告 | 91精品国产综合久久香蕉| 手机看片久久高清国产日韩| 日韩人妻无码一区二区三区久久 | 一本一道久久a久久精品综合 | 亚洲另类欧美综合久久图片区| 亚洲精品高清国产一线久久| 亚洲国产精品久久久久婷婷软件| 久久久久久久久66精品片| 2021久久国自产拍精品| 亚洲欧洲久久av| 一本大道加勒比久久综合| 久久人人爽人人爽人人片AV东京热| 精品久久久久久中文字幕| 久久精品国产清自在天天线| 久久精品一区二区国产| 国产免费久久精品99re丫y| 一本一道久久精品综合| 亚洲中文字幕久久精品无码APP | 久久久WWW成人免费毛片| 久久久久亚洲av无码专区导航| 久久99精品九九九久久婷婷| 国产精品久久久天天影视| 久久精品国产亚洲AV蜜臀色欲 | 亚洲午夜无码AV毛片久久| 99久久精品无码一区二区毛片 | 欧美一区二区精品久久| 精品久久久无码21p发布| 久久久久亚洲AV无码专区桃色 |