HDU 1956 POJ 1637 Sightseeing tour

混合图的欧拉回路判定方法:

1.首先判断基图是否连通,不连通的话表示不可能,否则进入下一步。

2.对于无向边,随便确定一个方向

3.确定好了之后,整张图就变成了有向图,计算每个节点的入度与出度

4.如果有一个节点的入度—出度是奇数,那么表示不可能,否则进入下一步

5.建立网络,新增一个原点s,和汇点t,然后建立网络

for(i=1; i<=M; i++)
    if(ff[i]==0)//如果是有向边
         AddEdge(u[i],v[i],1);
for(i=1; i<=N; i++)
{
    if(Ru[i]>Chu[i])
        AddEdge(i,t,(Ru[i]-Chu[i])/2);
    else
         AddEdge(s,i,(Chu[i]++-Ru[i])/2);
}            

6.计算网络最大流。

7.如果从S引出的边有流量的都是满流,那么表示存在,否则不存在。

8.把网络流中与S,T不关联的边找到,这些边中如果有流量等于1的边,那么将这些边反向,最终得到了一张欧拉图。

AC代码(网络最大流用了Dinic连续最短增广路算法):

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;


const int maxn=2000+10;
const int INF=0x7FFFFFFF;

struct Edge
{
    int from,to,cap,flow;
};
vector<Edge>edges;
vector<int>G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
int Ru[maxn];
int Chu[maxn];
int u[maxn],v[maxn],ff[maxn];
int father[maxn];
int m,s,t,tot;
int N,M;

//求出层次网络
bool BFS()
{
    memset(vis,0,sizeof(vis));
    queue<int>Q;
    Q.push(s);
    d[s]=0;
    vis[s]=1;
    while(!Q.empty())
    {
        int x=Q.front();
        Q.pop();
        for(int i=0; i<G[x].size(); i++)
        {
            Edge& e=edges[G[x][i]];
            if(!vis[e.to]&&e.cap>e.flow)
            {
                vis[e.to]=1;
                d[e.to]=d[x]+1;
                Q.push(e.to);
            }
        }
    }
    return vis[t];
}


//加边
void AddEdge(int from,int to,int cap)
{
    Edge r;
    r.from=from;
    r.to=to;
    r.cap=cap;
    r.flow=0;
    edges.push_back(r);
    Edge d;
    d.from=to;
    d.to=from;
    d.cap=0;
    d.flow=0;
    edges.push_back(d);
    m=edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}

//每个阶段来一次DFS增广
int DFS(int x,int a)
{
    if(x==t||a==0) return a;
    int flow=0,f;
    for(int i=cur[x]; i<G[x].size(); i++)
    {
        Edge& e=edges[G[x][i]];
        if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
        {
            e.flow+=f;
            edges[G[x][i]^1].flow-=f;
            flow+=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}

//多个阶段,多次建立层次网络。
int Maxflow(int ss,int tt)
{
    int flow=0;
    while(BFS())
    {
        memset(cur,0,sizeof(cur));
        flow+=DFS(ss,INF);
    }
    return flow;
}

int Find(int x)
{
    if(x!=father[x]) father[x]=Find(father[x]);
    return father[x];
}

int main()
{
    int T,flag,i;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        edges.clear();
        for(i=0; i<maxn; i++) G[i].clear();
        flag=1;
        s=0,t=N+1;//设置超级原点和超级汇点
        memset(Ru,0,sizeof(Ru));
        memset(Chu,0,sizeof(Chu));
        for(i=0;i<=N;i++) father[i]=i;
        tot=N;
        for(i=1; i<=M; i++)
        {
            scanf("%d%d%d",&u[i],&v[i],&ff[i]);
            int fx=Find(u[i]);
            int fy=Find(v[i]);
            if(fx!=fy)
            {
                father[fx]=fy;
                tot--;
            }
            Ru[v[i]]++;
            Chu[u[i]]++;
        }
        if(tot!=1) flag=0;
        if(flag)
        {
            for(i=1; i<=N; i++)
                if(abs(Ru[i]-Chu[i])%2==1)
                {
                    flag=0;
                    break;
                }
        }
        if(flag)
        {
            for(i=1; i<=M; i++)
                if(ff[i]==0)//如果是有向边
                    AddEdge(u[i],v[i],1);
            for(i=1; i<=N; i++)
            {
                if(Ru[i]>Chu[i])
                    AddEdge(i,t,(Ru[i]-Chu[i])/2);
                else
                    AddEdge(s,i,(Chu[i]++-Ru[i])/2);
            }
            Maxflow(s,t);
            for(i=0; i<edges.size(); i++)
                if(edges[i].from==s&&edges[i].cap!=edges[i].flow)
                {
                    flag=0;
                    break;
                }
        }
        if(flag) printf("possible
");
        else printf("impossible
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/4673490.html