HDU 3472 HS BDC 混合图欧拉路径 最大流

来源:互联网 发布:windows平板镜像下载 编辑:程序博客网 时间:2024/05/15 00:06

暑假的时候做过混合图的欧拉回路,然后这次碰到的是欧拉路径。
欧拉回路网上都有详细的题解,不多说了。
然后这题主要是“路径”,所以有些区别。路径的话就可能存在一个起点一个终点,它们的度数一定是奇数。
所以做这题分以下几步。
1. 判断连通性。
2. 把原来的无向边默认一个方向去修改两个点的入度和出度,然后在图中加一条反向边,容量为1。
3. 找到度数为奇数的点,只可能为2个或0个。如果为2个,在这两点随意连边,修改度数,再加反向边,容量为1。
4. 通过每个点的入度和出度差判断是和源点连边还是和汇点连边。
5. 跑最大流,判断是否满流。

这题的数据应该是挺水的,我跑了15ms就过了。
网上有些题解的代码好像是不对的。

#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <algorithm>#include <queue>using namespace std;const int MAXN = 100;const int MAXM = 5000;const int inf = 0x3f3f3f3f;char s[1500];int n,mp[MAXN][MAXN],head[MAXN];int dis[MAXN],in[MAXN],out[MAXN],tol,pre[MAXN];bool vis[MAXN];struct Edge{    int to,cap,flow,nex;    Edge(int to,int cap,int flow,int nex):to(to),cap(cap),flow(flow),nex(nex) {}    Edge() {}}edge[MAXM];void init(){    memset(in,0,sizeof in);    memset(out,0,sizeof out);    memset(head,-1,sizeof head);    memset(vis,0,sizeof vis);    tol=0;    for (int i=0;i<MAXN;i++) pre[i]=i;}int find(int p) { return pre[p]==p?p:pre[p]=find(pre[p]); }void join(int a,int b){    int u=find(a),v=find(b);    if (u!=v) pre[u]=v;}void addedge(int u,int v,int cap){    edge[tol]=Edge(v,cap,0,head[u]); head[u]=tol++;    edge[tol]=Edge(u,0,0,head[v]); head[v]=tol++;}int getnum(char ch){    return ch-'a'+1;}bool bfs(int s,int t){    memset(dis,-1,sizeof dis);    dis[s]=0;    queue<int> que;    que.push(s);    while (!que.empty())    {        int u=que.front();que.pop();        for (int i=head[u];~i;i=edge[i].nex)        {            int v=edge[i].to;            if (dis[v]==-1 && edge[i].cap>edge[i].flow)            {                dis[v]=dis[u]+1;                if (v==t) return true;                que.push(v);            }        }    }    return false;}int dfs(int u,int t,int cap){    if (u==t) return cap;    int flow=0,f;    for (int i=head[u];~i;i=edge[i].nex)    {        int v=edge[i].to;        if (dis[v] == dis[u]+1 && edge[i].cap>edge[i].flow)        {            f=dfs(v,t,min(cap-flow,edge[i].cap-edge[i].flow));            edge[i].flow += f;            edge[i^1].flow -= f;            flow += f;            if (flow == cap) break;        }    }    if (!flow) dis[u]=-1;    return flow;}int dicnic(int s,int t){    int flow=0,a;    while (bfs(s,t))        while ((a=dfs(s,t,inf))>0)            flow+=a;    return flow;}int main(){    int t,tt=0,tag;    cin>>t;    while (t--)    {        init();        cin>>n;        for (int i=1;i<=n;i++)        {            scanf("%s%d",s,&tag);            int a=getnum(s[0]);            int b=getnum(s[strlen(s)-1]);            vis[a]=vis[b]=true;            out[a]++;            in[b]++;            join(a,b);            if (tag == 1)                addedge(b,a,1);        }        int cnt=0,sum=0,v1=0,v2=0;        bool flag=false;        for (int i=1;i<=26;i++)            if (vis[i])                for (int j=1;j<=26;j++)                    if (vis[j] && find(i)!=find(j))                        flag=true;        for (int i=1;i<=26;i++)        {            int k=in[i]-out[i];            if (k&1)            {                cnt++;                if (v1) v2=i;                else v1=i;            }        }        printf("Case %d: ",++tt);        if (cnt != 2 && cnt!=0) flag=true;        if (cnt == 2)        {            out[v1]++;            in[v2]++;            addedge(v2,v1,1);        }        if (flag)        {            printf("Poor boy!\n");            continue;        }        for (int i=1;i<=26;i++)        {            int k=in[i]-out[i];            if (!k) continue;            if (k>0) addedge(0,i,k/2) , sum+=k/2;            if (k<0) addedge(i,27,-k/2);        }        int ans=dicnic(0,27);        if (ans == sum )            printf("Well done!\n");        else            printf("Poor boy!\n");    }    return 0;}