UVAlive5135_Mining Your Own Business

來源:互聯網
上載者:User

標籤:style   blog   color   os   for   io   

好題。給一個無向圖,求最少染黑多少個點後,使得任意刪除一個點,每一個點都有與至少一個黑點聯通。

一開始的確不知道做。看白書,對於一個聯通分量,如果它有兩個或以上的割點,那麼這個分量中間的任何一個點都是不需要染色的。如果這個聯通分量恰好有一個割點,那麼這個分量需要對其中任何一個非割點染色,如果分量沒有割點,那麼任意取兩個染色即可。

理解也不難,因為最多隻是刪除一個點,所以假如刪除的不是割點,分量裡面是絕對聯通的,同時還可以通過割點對外面進行聯通,如果刪除的是割點,那麼外面的與裡面的不聯通,那麼這時就需要裡面至少有一個黑點了。如果有兩個割點,顯然,無論你去掉哪一個點,這個分量都是與外面聯通的。

有了這個思路題目就簡單了。

 

 

召喚代碼君:

 

 

解法一:找出所有的聯通分量,判斷每一個連通分量的割點數,更新答案。

#include <iostream>#include <cstdio>#include <cstring>#include <vector>#define maxn 201000typedef long long ll;using namespace std;int first[maxn],next[maxn],to[maxn],edge;//graphvector<int> bcc[maxn];int N,bccnum;//the bcc dataint iscut[maxn],belong[maxn],d[maxn],low[maxn],child;int U[maxn],V[maxn],stack[maxn],top;//stackint n,m,cas=0,T;ll ans,tot;void _init(){    ans=1,tot=0,edge=-1,child=bccnum=0,top=0;    for (int i=1; i<=n; i++) first[i]=-1,d[i]=low[i]=iscut[i]=belong[i]=0;}void addedge(int uu,int vv){    edge++;    to[edge]=vv,next[edge]=first[uu],first[uu]=edge;    edge++;    to[edge]=uu,next[edge]=first[vv],first[vv]=edge;}void dfs(int cur,int fa){    d[cur]=low[cur]=d[fa]+1;    for (int i=first[cur]; i!=-1; i=next[i])    {        if (to[i]==fa) continue;        if (!d[to[i]])        {            if (fa==0) child++;            top++; U[top]=cur,V[top]=to[i];            dfs(to[i],cur);            low[cur]=min(low[cur],low[to[i]]);            if (low[to[i]]>=d[cur])            {                iscut[cur]=1;                bccnum++,bcc[bccnum].clear();                for (;;top--)                {                    if (belong[U[top]]!=bccnum) belong[U[top]]=bccnum,bcc[bccnum].push_back(U[top]);                    if (belong[V[top]]!=bccnum) belong[V[top]]=bccnum,bcc[bccnum].push_back(V[top]);                    if (U[top]==cur && V[top]==to[i])                    {                        top--;                        break;                    }                }            }        }        else low[cur]=min(low[cur],d[to[i]]);    }    if (fa==0 && child==1) iscut[cur]=0;}int main(){    while (scanf("%d",&m) && (m))    {        n=-1;        for (int i=1; i<=m; i++)        {            scanf("%d%d",&U[i],&V[i]);            n=max(n,max(U[i],V[i]));        }        _init();        for (int i=1; i<=m; i++) addedge(U[i],V[i]);        for (int i=1; i<=n; i++)            if (!d[i])            {                if (first[i]==-1)                {                    tot++;                    continue;                }                child=0;                dfs(i,0);            }        for (int i=1; i<=bccnum; i++)        {            int cutnum=0;            for (unsigned j=0; j<bcc[i].size(); j++)                if (iscut[bcc[i][j]]) cutnum++;            if (cutnum==1)            {                tot++;                ans*=bcc[i].size()-1;            }            else if (cutnum==0)            {                tot+=2;                ll tmp=bcc[i].size();                ans*=tmp*(tmp-1)/2;            }        }        printf("Case %d: %lld %lld\n",++cas,tot,ans);    }    return 0;

 

解法二:標記所有割點,每次從非割點出發,看能走到多少非割點,而且總共與多少割點相鄰,(其實也就是遍曆了一遍聯通分量,不過實現簡單一些)。

#include <iostream>#include <cstdio>#include <cstring>#define maxn 200200typedef long long ll;using namespace std;int first[maxn],to[maxn],next[maxn],edge;int U[maxn],V[maxn];int d[maxn],low[maxn],tag[maxn];bool iscut[maxn],vis[maxn];int n,m,tot,child,sum,cut;ll ans;void _init(){    tot=0,ans=1,edge=-1;    for (int i=1; i<=n; i++)        first[i]=-1,iscut[i]=vis[i]=false,tag[i]=low[i]=d[i]=0;}void addedge(int uu,int vv){    edge++;    to[edge]=vv,next[edge]=first[uu],first[uu]=edge;    edge++;    to[edge]=uu,next[edge]=first[vv],first[vv]=edge;}void dfs(int cur,int fa){    d[cur]=low[cur]=d[fa]+1;    for (int i=first[cur]; i!=-1; i=next[i])    {        if (to[i]==fa) continue;        if (!d[to[i]])        {            if (fa==0) child++;            dfs(to[i],cur);            low[cur]=min(low[cur],low[to[i]]);            if (low[to[i]]>=d[cur]) iscut[cur]=true;        }        else low[cur]=min(low[cur],d[to[i]]);    }    if (fa==0 && child==1) iscut[cur]=false;}void visit(int cur,int TAG){    sum++,vis[cur]=true;    for (int i=first[cur]; i!=-1; i=next[i])    {        if (iscut[to[i]] && tag[to[i]]!=TAG) cut++,tag[to[i]]=TAG;            else if (!iscut[to[i]] && !vis[to[i]]) visit(to[i],TAG);    }}int main(){    int cas=0;    while (scanf("%d",&m) && (m))    {        n=0;        for (int i=1; i<=m; i++) scanf("%d%d",&U[i],&V[i]),n=max(n,max(U[i],V[i]));        _init();        for (int i=1; i<=m; i++) addedge(U[i],V[i]);        for (int i=1; i<=n; i++)            if (!d[i])            {                child=0;                dfs(i,0);            }        for (int i=1; i<=n; i++)            if (!vis[i] && !iscut[i])            {                cut=sum=0;                visit(i,i);                if (cut==0) tot+=2,ans*=(ll)sum*(sum-1)/2;                    else if (cut==1) tot++,ans*=sum;            }        printf("Case %d: %d %lld\n",++cas,tot,ans);    }    return 0;}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.