我的最小樹形圖模板(已更新)

來源:互聯網
上載者:User

這個寫法複雜度為O(ElogE+V*V),關鍵耗時在排序上,當邊權範圍相對小的時候,用基數排序最佳化,做到O(V*V)*常數,這個效率非常可觀,基本上如果滿足邊權要求就用這個模板了,希望有人幫我最佳化下普通情況下的排序。。。

之後再給出普通版的模板,先貼這個基數排序最佳化的

代碼(UVA 11183
- Teen Girl Squad):

#include<cstdio>using namespace std;const int mm=44444;const int mn=1111;struct edge{    int s,t,w;}g[mm],h[mm];int head[mm],next[mm];int p[mn],q[mn],mark[mn],fp[mn],from[mn],vis[mn],in[mn],w[mn],ans,sum;int i,j,k,n,m,e,r,mw,t,cas=0;bool huan;inline void addedge(int u,int v,double c){    g[e].s=u,g[e].t=v,g[e].w=c,next[e]=head[u],head[u]=e++;    if(c>mw)mw=c;}void dfs(int u){    ++sum,vis[u]=1;    for(int i=head[u];i>=0;i=next[i])        if(!vis[g[i].t])dfs(g[i].t);}inline void init(int& a){    char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    for (a=0; ch>='0'&&ch<='9'; ch=getchar()) a=a*10+ch-48;}void mysort(){    int i;    for(i=0;i<=n;++i)q[i]=0;    for(i=0;i<=mw;++i)p[i]=0;    for(i=0;i<e;++i)++q[g[i].t],++p[g[i].w];    for(i=1;i<=n;++i)q[i]+=q[i-1];    for(i=n;i>0;--i)q[i]=q[i-1];    q[0]=0;    for(i=1;i<=mw;++i)p[i]+=p[i-1];    for(i=mw;i>0;--i)p[i]=p[i-1];    p[0]=0;    for(i=0;i<e;++i)h[p[g[i].w]++]=g[i];    for(i=0;i<e;++i)g[q[h[i].t]++]=h[i];}int main(){    init(t);    while(t--)    {        init(n),init(m),--n;        for(i=e=mw=0;i<=n;++i)head[i]=-1;        while(m--)        {            init(i),init(j),init(k);            if(i!=j)addedge(i,j,k);        }        for(sum=i=0;i<=n;++i)vis[i]=0;        dfs(0);        if(sum<n+1)        {            printf("Case #%d: Possums!\n",++cas);            continue;        }        mysort();        for(i=0;i<=n;++i)fp[i]=p[i]=-1,in[i]=vis[i]=0,mark[i]=i;        for(i=0;i<e;++i)            if(p[g[i].t]<0)p[g[i].t]=i;        huan=1,ans=sum=0;        while(huan)        {            huan=0;            for(i=1;i<=n;++i)                if(fp[j=mark[i]]>=0)                {                    if(fp[i]<0)in[i]+=w[j],mark[i]=mark[mark[i]];                    else                    {                        in[i]+=w[i],ans+=w[i];                        if(g[++p[fp[i]]].t!=fp[i])p[fp[i]]=-1;                    }                }            for(i=0;i<=n;++i)fp[i]=-1,vis[i]=0;            for(i=1;i<=n;++i)                if(p[i]>=0)                {                    if(fp[j=mark[i]]<0||(fp[j]>=0&&w[j]>g[p[i]].w-in[i]))                       w[j]=g[p[i]].w-in[i],fp[j]=i,from[j]=mark[g[p[i]].s];                }            for(sum=0,i=1;i<=n;++i)                if(fp[i]>=0)sum+=w[i];            for(i=1;i<=n;++i)                if(!vis[i])                {                    r=0,j=i;                    while(j>0&&vis[j]>=0)                    {                        if(vis[j]>0)                        {                            huan=1;                            while(q[--r]!=j)mark[q[r]]=j,vis[q[r]]=-1;                            vis[j]=-1;                        }                        else if(!vis[j])vis[q[r++]=j]=1;                        if(fp[j]>=0)j=from[j];                        else j=-1;                    }                    while(r--)vis[q[r]]=fp[q[r]]=-1;                }        }        printf("Case #%d: %d\n",++cas,ans+sum);    }    return 0;}

普通版本1(這個版本改自傻崽大神的模板,速度還行,代碼簡短):

#include<cstdio>#include<cmath>#define type intusing namespace std;const int mm=44444;const int mn=1111;const int oo=1000000000;type c[mm],in[mn],ans;int s[mm],t[mm],id[mn],pre[mn],q[mn];type Directed_MST(int root,int NV,int NE){    type ret=0;    int i,j,u,v,cnt,r;    while(1)    {        for(i=0;i<=NV;++i)in[i]=oo;        for(i=0;i<NE;++i)            if((u=s[i])!=(v=t[i])&&in[v]>c[i])                pre[v]=u,in[v]=c[i];        pre[root]=-1,in[root]=0;        for(i=1;i<=NV;++i)            if(in[i]==oo)return -1;        for(i=1;i<=NV;++i)id[i]=-1,ret+=in[i];        for(cnt=0,i=1;i<=NV;++i)            if(id[i]<0)            {                r=0,j=i;                while(j>=0&&id[j]<0)                {                    if(id[j]==-2)                    {                        id[j]=++cnt;                        while(q[--r]!=j)id[q[r]]=cnt;                    }                    else id[q[r++]=j]=-2,j=pre[j];                }                while(r--)id[q[r]]=++cnt;            }        if(cnt==NV)break;        for(i=0;i<NE;++i)        {            j=t[i],s[i]=id[s[i]],t[i]=id[t[i]];            if(s[i]!=t[i])c[i]-=in[j];        }        NV=cnt;        root=id[root];    }    return ret;}int main(){    int n,m,e,T,cas=0;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m),--n;        e=0;        while(m--)scanf("%d%d%d",&s[e],&t[e],&c[e]),e+=(s[e]!=t[e]);        ans=Directed_MST(0,n,e);        if(ans<0)printf("Case #%d: Possums!\n",++cas);        else printf("Case #%d: %d\n",++cas,ans);    }    return 0;}

普通版本2(這個自己寫的,與上一個版本相差無幾,用多個點迴圈替換掉邊迴圈,當邊多的時候有優勢,邊少反而慢了):

#include<cstdio>#include<cmath>#define type intusing namespace std;const int mm=44444;const int mn=1111;type c[mm],in[mn],w[mn],ans;int s[mm],t[mm],id[mn],pre[mn],q[mn],vis[mn];type Directed_MST(int root,int NV,int NE){    type ret=0,sum=0,tmp;    int i,j,u,v,r;    bool huan=1;    for(i=0;i<=NV;++i)in[i]=0,id[i]=i,pre[i]=-1;    while(huan)    {        for(i=0;i<=NV;++i)            if(pre[j=id[i]]>=0)            {                if(pre[i]<0)in[i]+=w[j],id[i]=id[j];                else in[i]+=w[i],ret+=w[i];            }        for(i=0;i<=NV;++i)pre[i]=-1,vis[i]=0;        for(i=0;i<NE;++i)            if((u=id[s[i]])!=(v=id[t[i]])&&(w[v]>(tmp=c[i]-in[t[i]])||pre[v]<0))                pre[v]=u,w[v]=tmp;        for(i=1;i<=NV;++i)            if(i!=root&&id[i]==i&&pre[i]<0)return -1;        for(pre[root]=-1,sum=i=0;i<=NV;++i)            if(pre[i]>=0)sum+=w[i];        for(i=huan=0;i<=NV;++i)            if(!vis[i])            {                r=0,j=i;                while(j>=0&&vis[j]>=0)                {                    if(vis[j]>0)                    {                        while(q[--r]!=j)id[q[r]]=j,vis[q[r]]=-1;                        huan=1,vis[j]=-1;                    }                    else vis[q[r++]=j]=1,j=pre[j];                }                while(r--)vis[q[r]]=pre[q[r]]=-1;            }    }    return ret+sum;}int main(){    int n,m,e,T,cas=0;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m),--n;        e=0;        while(m--)scanf("%d%d%d",&s[e],&t[e],&c[e]),e+=(s[e]!=t[e]);        ans=Directed_MST(0,n,e);        if(ans<0)printf("Case #%d: Possums!\n",++cas);        else printf("Case #%d: %d\n",++cas,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.