• <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>
            posts - 5,  comments - 5,  trackbacks - 0
                 把自己原來做過的幾道感覺不錯的圖論題貼過來。
                 
            [無向圖點雙][POJ2942]Knights of the Round Table

            題目大意:有N個騎士,給出有兩兩之間有仇恨的關系,要求安排一種環形座次使得總人數為奇數而且其實之間不會發生沖突。

                題解:首先根據給出的關系可以確定兩兩之間沒有仇恨的關系,然后根據該關系構建圖。容易知道,最后安排的人必定在同一個點雙連通分量當中(否則不會形成環)。然后要在每個點雙當中尋找一個奇圈。直接給出兩個霸氣的定理:1.如果一個點雙連通分量中存在奇圈,那么整個點雙連通分量的所有點必定也在一個奇圈中。

            2.一個點雙連通分量如果不是二分圖則一定包含奇圈


              1#include <iostream>
              2#include <cstdio>
              3#include <algorithm>
              4#include <vector>
              5#include <stack>
              6using namespace std;
              7int N,M;
              8bool discnt[1005][1005],Stay[1005];
              9vector<int> adj[1005];
             10int Color,Time,dfn[1005],low[1005],color[1005],bw[1005],Ans;
             11stack< pair<int,int> > Stack;
             12
             13bool isDiv(int u,int _bw){
             14    bw[u]=_bw;
             15    int i,node;
             16    for(i=0;i<adj[u].size();i++){
             17        node=adj[u][i];
             18        if(color[node]==Color){
             19            if(bw[node]==-1){
             20                if(!isDiv(node,!_bw))    return false;
             21            }

             22            else if(bw[node]==_bw) return false;
             23        }

             24    }

             25    return true;
             26}

             27
             28void dfs(int u,int fa){
             29    int i,j,node;
             30    dfn[u]=low[u]=++Time;
             31    for(i=0;i<adj[u].size();i++){
             32        node=adj[u][i];
             33        if(!dfn[node]){
             34            Stack.push(make_pair(u,node));
             35            dfs(node,u);
             36            low[u]=min(low[u],low[node]);
             37            if(low[node]>=dfn[u]){
             38                ++Color;
             39                pair<int,int> edge_1=make_pair(node,u);
             40                pair<int,int> edge_2=make_pair(u,node);
             41                while(Stack.top()!=edge_1&&Stack.top()!=edge_2&&!Stack.empty()){
             42                    color[Stack.top().first]=color[Stack.top().second]=Color;
             43                    Stack.pop();
             44                }

             45                color[Stack.top().first]=color[Stack.top().second]=Color;
             46                Stack.pop();
             47                memset(bw,-1,sizeof(bw));
             48                if(!isDiv(u,1)){
             49                    for(j=1;j<=N;j++){
             50                        if(color[j]==Color){
             51                            Stay[j]=true;
             52                        }

             53                    }

             54                }

             55            }

             56        }

             57        else if(node!=fa){
             58
             59            low[u]=min(low[u],dfn[node]);
             60        }

             61    }

             62}

             63            
             64
             65int main(){
             66
             67    while(scanf("%d%d",&N,&M)!=EOF){
             68        if(N+M==0break;
             69        int i,j,a,b;
             70        for(i=1;i<=N;i++)   adj[i].clear();
             71        memset(discnt,false,sizeof(discnt));
             72        for(i=1;i<=M;i++){
             73            scanf("%d%d",&a,&b);
             74            discnt[a][b]=discnt[b][a]=true;
             75        }

             76        for(i=1;i<=N;i++){
             77            for(j=1;j<=N;j++){
             78                if(i==j)    continue;
             79                if(!discnt[i][j]){
             80                    adj[i].push_back(j);
             81                }

             82            }

             83        }

             84        memset(dfn,0,sizeof(dfn));
             85        memset(low,0,sizeof(low));
             86       
             87        memset(Stay,0,sizeof(Stay));
             88        memset(color,0,sizeof(color));
             89        Stack=stack< pair<int,int> >();
             90        Color=0;
             91        for(i=1;i<=N;i++){
             92            if(!dfn[i]){
             93                Time=0;
             94                dfs(i,0);
             95            }

             96        }

             97        Ans=N;
             98        for(i=1;i<=N;i++)   if(Stay[i]) Ans--;
             99        printf("%d\n",Ans);
            100    }

            101    return 0;
            102}


            校賽時的I題,Special Fish

            困惑的地方:比賽時候我們想到KM,然后想起一句話,KM只能做完備匹配,于是沒有寫。后來發現大家都是直接一遍KM就過了,回來我寫成費用流發現不行。答案不應該是最后的cost而應該是 Max(cost),然后被tclsm大牛質疑了,于是有如下討論研究:

               關鍵點:這個圖不是完備匹配。

               1)為什么KM可以直接做就AC了?KM做出來不是完備匹配么?NO!KM做出來還是完備匹配,不過對于非完備的用邊權為0的邊代替了。那么去掉這些邊權為0的邊可以么?答案是不可以,見下文

               2)用費用流做:

               對于每個點i,我拆成了i和i'然后用了兩種方式建圖
            1.s-> all i cost =0 cap=1
               all i'->t cost =0 cap=1
               所有i可以攻擊j的 i->j' cost=-(vali^valj) cap=1
               做費用流,wa掉,部分比答案小
            2.s-> all i cost =0 cap=1
               all i'->t cost =0 cap=1
               所有i可以攻擊j的 i->j' cost=vali^valj cap=1
               所有i不可以攻擊j的 i->j' cost=0 cap=1
               做費用流 AC

            為什么會出現這種問題?由于我們做的是最小費用最大流,所以前提條件是流量最大,之后費用最小。于是這個題的關鍵點終于出來了--最小費用的情況下是不是保證最大流?直觀的看貌似是的,因為如果最小費用的情況不是最大流的話,那么由于費用都是負數,可以再找一條增廣路來減小費用。直接看這個好像沒有什么問題,而且之前和zz討論他也以這個為論點。但是在說這句話的時候忘記了一個很重要的問題--后向邊!!!從后向邊走費用一定是負數么?No!所以這么下來未必會減少費用而最后cost也未必是答案。

            改進方法:1.使用模型2是的原圖可以達到最大流 2.取Max (cost)

             

            感謝tclsm大牛的指點,感謝好友zz的討論~


            POJ 3177 邊雙連通分量
            題目大意:給一個無向圖,求最少添加多少條邊可以使得任意兩個頂點間至少有兩條不相交的路徑。

                題解:如果存在兩個頂點,他們之間只有一條路徑或者所有路徑相交,那么必定有橋。所以對于原圖收縮邊雙連通分量,然后形成一棵樹,答案就是樹中(葉子節點個數+1)/2 (正確性:不會嚴格證明,畫個圖葉子之間兩兩連一下感覺沒問題...)


             1#include <iostream>
             2#include <vector>
             3using namespace std;
             4int t,f,r,dfn[5001],low[5001],bic[5001],color,indo[5001],ans;
             5bool brige[5001][5001];
             6vector<int> adj[5001];
             7vector< pair<int,int> > Brige;
             8
             9void dfs(int u,int v){
            10    dfn[u]=low[u]=++t;
            11    int node;
            12    for(int i=0;i<adj[u].size();i++){
            13        node=adj[u][i];
            14        if(!dfn[node]){
            15            dfs(node,u);
            16            low[u]=min(low[u],low[node]);
            17            if(low[node]>dfn[u]){
            18                brige[node][u]=brige[u][node]=true;
            19                Brige.push_back(make_pair(u,node));
            20            }

            21        }

            22        else if(node!=v){
            23            low[u]=min(low[u],dfn[node]);
            24        }

            25    }

            26}

            27
            28void floodfill(int u){
            29    bic[u]=color;
            30    int node;
            31    for(int i=0;i<adj[u].size();i++){
            32        node=adj[u][i];
            33        if(!bic[node]&&!brige[u][node]){
            34            floodfill(node);
            35        }

            36    }

            37}

            38            
            39
            40int main(){
            41    scanf("%d%d",&f,&r);
            42    int i,j,a,b;
            43    for(i=1;i<=r;i++){
            44        scanf("%d%d",&a,&b);
            45        adj[a].push_back(b);
            46        adj[b].push_back(a);
            47    }

            48    dfs(1,0);
            49    for(i=1;i<=f;i++){
            50        if(!bic[i]){
            51            ++color;
            52            floodfill(i);
            53        }

            54    }

            55    for(i=0;i<Brige.size();i++){
            56        indo[bic[Brige[i].first]]++;
            57        indo[bic[Brige[i].second]]++;
            58    }

            59    for(i=1;i<=color;i++){
            60        if(indo[i]==1) ans++;
            61    }

            62    printf("%d\n",(ans+1)/2);
            63    return 0;
            64}

            posted on 2010-08-01 19:55 OpenWings 閱讀(335) 評論(0)  編輯 收藏 引用
            <2025年7月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            隊員

            最新評論

            • 1.?re: 杭州G題的代碼
            • @此最相思
              271763295,最近事情有點多回復晚了不好意思
            • --fatboy_cw
            • 2.?re: 杭州G題的代碼
            • 您有QQ么 在線請教一下 您的代碼我好幾個沒看懂...
            • --此最相思
            • 3.?re: 杭州G題的代碼
            • @OpenWings
              這題是不是求經過幾個連通分量?
            • --此最相思
            • 4.?re: 杭州G題的代碼
            • @此最相思
              對無向圖收縮點雙連通分量以后,把每個分量連接到對應割點上,對于詢問用tarjan處理lca(rmq貌似還得加個虛根),然后用距離除2即可。
            • --OpenWings
            • 5.?re: 杭州G題的代碼
            • 縮點以后怎么處理 能說的詳細些么? 希望能舉個具體例子說說 謝謝
            • --此最相思

            閱讀排行榜

            評論排行榜

            91精品国产9l久久久久| 中文字幕无码av激情不卡久久 | 亚洲欧美日韩久久精品第一区| 亚洲欧美日韩精品久久亚洲区| 欧美国产成人久久精品| 99久久精品国产高清一区二区| 国产精品九九久久精品女同亚洲欧美日韩综合区 | 亚洲国产一成人久久精品| 久久精品亚洲日本波多野结衣| 亚洲狠狠综合久久| 中文精品久久久久人妻不卡| 一本伊大人香蕉久久网手机| 久久综合亚洲色HEZYO社区| 一级做a爱片久久毛片| 一本久久a久久精品亚洲| 国产精品久久久久久久午夜片| 日韩精品久久无码人妻中文字幕| 99久久99久久精品国产片果冻| 中文字幕无码久久久| 久久婷婷成人综合色综合| 国产精品久久久久久久久软件| 国产精品久久自在自线观看| 久久综合香蕉国产蜜臀AV| 国产精品久久影院| 久久久久女教师免费一区| 久久人做人爽一区二区三区 | 久久久久久精品久久久久| 亚洲国产精品高清久久久| 色综合合久久天天综合绕视看| 久久亚洲天堂| 国产亚洲婷婷香蕉久久精品| 国产精品女同一区二区久久| 久久午夜免费视频| 久久久久久久波多野结衣高潮 | 一本色综合久久| 久久久久18| 亚洲欧美精品一区久久中文字幕| 激情五月综合综合久久69| 精品人妻伦九区久久AAA片69| 国产午夜精品久久久久九九电影| 久久久综合九色合综国产|