HDOJ3472-混合图欧拉路的求解

我的访问量绝大部分来自于几篇关于欧拉(回)路的博客,唉~

欧拉路又来了!

//将字母看成结点,单词如victoria看成边<v,a>,倒过来有意义的单词为无向边,否则为有向边,不难想串接单词就是求是否有欧拉路。
//求欧拉路可以通过加一条边来转化为求欧拉回路(同HDOJ1637),建好网络用最大流来解即可
//要注意的是,这题在求解之前应该判断一下图是否连通,这里用的是并查集来判断的。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int NN=100;
const int MM=100000;
const int INF=0x3fffffff;

int S,T,NV,n,sum,en,p[NN],head[NN],in[NN],out[NN],ex[MM],ey[MM];
bool showed[NN];
struct Edge{
   int u,v,f,next;
   Edge() {}
   Edge(int uu,int vv,int ff,int tt): u(uu),v(vv),f(ff),next(tt) {}
}e[MM];
inline void add(int u,int v,int f)
{
    e[en]=Edge(u,v,f,head[u]);
    head[u]=en++;
    e[en]=Edge(v,u,0,head[v]);
    head[v]=en++;
}

int find(int x)
{
    if (p[x]==0) return p[x]=x;
    if (p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

bool init()
{
    int i,l,w,x,y,degree,k1,k2,cnt=0;
    char str[32];

    scanf("%d",&n);
    en=0;
    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    for (i=1; i<=26; i++) p[i]=showed[i]=0;
    for (i=1; i<=n; i++)
    {
        scanf("%s %d",str,&w);
        l=strlen(str)-1;
        x=str[0]-96;
        y=str[l]-96;
        showed[x]=showed[y]=1;
        p[find(y)]=find(x);
        out[x]++; in[y]++;
        if (w==1) add(x,y,1);
    }

    k2=find(x);
    for (i=1; i<=26; i++) if (showed[i] && find(i)!=k2) break;
    if (i<=26) return false;

    sum=S=0; T=27; NV=28;
    for (i=1; i<=26; i++)
    {
        if ((out[i]-in[i])%2)
        {
            cnt++;
            if (cnt==1) k1=i;
            else        k2=i;
        }
    }
    if (cnt!=0 && cnt!=2) return false;
    if (cnt==2) { out[k1]++; in[k2]++; add(k1,k2,1); }
    for (i=1; i<=26; i++)
    {
        degree=out[i]-in[i];
        if (cnt>2) return false;
        degree>>=1;
        if (degree>0) add(S,i,degree),sum+=degree;
        else if (degree)   add(i,T,-degree);
    }
    return true;
}

int cur[NN],gap[NN],dis[NN],pre[NN];
int sap()
{
    int maxflow=0;
    for(int i=0; i<NV; i++)
    {
        dis[i]=gap[i]=0;
        cur[i]=head[i];
    }
    int u=pre[S]=S;
    int aug=INF;
    gap[0]=NV;
    while(dis[S]<NV)
    {
loop:
        for(int &i=cur[u]; i!=-1; i=e[i].next)
        {
            int v=e[i].v;
            if(e[i].f && dis[u]==dis[v]+1)
            {
                if (aug>e[i].f) aug=e[i].f;
                pre[v]=u;
                u=v;
                if(v==T)
                {
                    maxflow+=aug;
                    for(u=pre[u]; v!=S; v=u,u=pre[u])
                    {
                        e[cur[u]].f-=aug;
                        e[cur[u]^1].f+=aug;
                    }
                    aug=INF;
                }
                goto loop;
            }
        }
        int min_dis=NV;
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            int v=e[i].v;
            if(e[i].f && min_dis>dis[v])
            {
                cur[u]=i;
                min_dis=dis[v];
            }
        }
        if(--gap[dis[u]]==0) break;
        gap[dis[u]=min_dis+1]++;
        u=pre[u];
    }
    return maxflow;
}

int main()
{
    int T,cas=0;
    scanf("%d",&T);
    while (T--)
    {
        printf("Case %d: ",++cas);
        if (!init())
        {
            puts("Poor boy!");
            continue;
        }
        if (sap()==sum) puts("Well done!");
        else            puts("Poor boy!");
    }
}


你可能感兴趣的:(struct,网络,SAP)