HDU 4687 带花树

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
#define N 1010
int n,m;
int link[N],fa[N];
int base[N];//属于哪朵花
int q[N],inq[N];
int g[N][N];
int inflower[N];
int vis[N];
int head,tail;


struct node
{
    int u,v;
}edge[N];


void contract(int x,int y)
{
    memset(vis,0,sizeof(vis));
    memset(inflower,0,sizeof(inflower));
#define pre fa[link[i]]
    int lca,i;//lca公共祖先
    for(i=x;i;i=pre)
    {
        i=base[i];
        vis[i]=1;
    }//找x走过的路
    
    for(i=y;i;i=pre)
    {
        i=base[i];
        if(vis[i])
        {
            lca=i;
            break;
        }
    }//找y走过的路,若和X重叠则该点为公共祖先
    for(i=x;base[i]!=lca;i=pre)
    {
        if(base[pre]!=lca)
            fa[pre]=link[i];//对于bfs树种父边是匹配的点,那么久往下走
        inflower[base[i]]=1;
        inflower[base[link[i]]]=1;//将两点入花
    }
    for(i=y;base[i]!=lca;i=pre)
    {
        if(base[pre]!=lca)
            fa[pre]=link[i];
        inflower[base[i]]=1;
        inflower[base[link[i]]]=1;
    }
#undef pre
    if(base[x]!=lca)
        fa[x]=y;
    if(base[y]!=lca)
        fa[y]=x;
    for(i=1;i<=n;i++)
    {
        if(inflower[base[i]])
        {
            base[i]=lca;
            if(!inq[i])
            {
                q[tail++]=i;
                inq[i]=1;
            }
        }
    }
}


bool bfs(int u)
{
    int i,j,v,f;
    for(i=0;i<=n;i++)
    {
        fa[i]=-1;
        base[i]=i;
        inq[i]=0;
    }
    head=0,tail=1;//q.clear();
    q[0]=u;
    inq[u]=1;
    while(head<tail)
    {
        int b=q[head++];
        for(v=1;v<=n;v++)
        {
            if( g[b][v]==0 || base[b]==base[v] || link[b]==v )//当不是可连接的边,花的祖先是一样的时候,或者已经连接了的边都TMD没有意义
                continue;
            if( b == v || (link[v]!=-1 && fa[link[v]]!=-1))
                contract(b,v);
            else if(fa[v]==-1)
            {
                fa[v]=b;
                if(link[v]!=-1)
                {
                    q[tail++]=link[v];
                    inq[link[v]]=1;
                }
                else
                {
                    int x,y;
                    while(v!=-1)
                    {
                        y=fa[v];
                        x=link[y];
                        link[y]=v;
                        link[v]=y;
                        v=x;
                    }
                    return true;
                }
            }
        }
    }
    return false;
}


int maxmatch()
{
    int sum=0;
    memset(link,-1,sizeof(link));
    for(int i=1;i<=n;i++)
    {
        if(link[i]==-1&&bfs(i))
            sum++;
    }
    return sum;
}


int main()
{
    //freopen("e://in.txt","r",stdin);
    //freopen("e://out.txt","w",stdout);
    int i,j,u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(g,0,sizeof(g));
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            g[u][v] = g[v][u] =1;
            edge[i].u = u;
            edge[i].v = v;
        }
        
        int max=maxmatch();
        vector<int>ans;
        ans.clear();
        for(i=1;i<=m;i++)
        {
            int x=edge[i].u;
            int y=edge[i].v;
            memset(g,0,sizeof(g));
            for(j=1;j<=m;j++)
            {
                if(j==i)
                    continue;
                int a=edge[j].u;
                int b=edge[j].v;
                if(x==a || x==b || y==a || y==b)
                    continue;
                g[a][b]=g[b][a]=1;
            }
            int smax = maxmatch();
            if(smax != max-1)
                ans.push_back(i);
        }
        int sz=ans.size();
        printf("%d\n",sz);
        if(sz)
            printf("%d",ans[0]);
        for(i=1;i<sz;i++)
            printf(" %d",ans[i]);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值