01分数规划->建模->最大权闭合子图。重在建模,就是一个边选了,两个点都要选

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=40018,inf=1e9;
struct edg{
    int nxt,to;
    double f;
}e[maxn];
int cnt,vis[maxn],head,tail,q[maxn],S,T,n,m,t,last[maxn],d[maxn];
double l,r,mid;
void add(int x,int y,double z){
    ++t;e[t].nxt=last[x];last[x]=t;e[t].to=y;e[t].f=z;
    ++t;e[t].nxt=last[y];last[y]=t;e[t].to=x;e[t].f=0;
}
struct dui{
    int from,to;
}qq[maxn];
int bfs(){
    head=tail=0;
    memset(d,-1,sizeof(d));
    q[++tail]=S;d[S]=0;
    while(head<tail){
        int u=q[++head];
        for(int i=last[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(e[i].f&&d[v]==-1){
                d[v]=d[u]+1;
                q[++tail]=v;
            }
        }
    }
    return d[T]!=-1;
}
double dfs(int x,double h){
    if(x==T){return h;}
    double tmp=0,cp;
    for(int i=last[x];i;i=e[i].nxt){
        int v=e[i].to;
        if(e[i].f&&d[v]==d[x]+1){
            cp=dfs(v,min(h-tmp,e[i].f));
            e[i].f-=cp;e[i^1].f+=cp;tmp+=cp;
            if(tmp==h){return tmp;}
        }
    }
    if(!tmp)d[x]=-2;
    return tmp;
}
int pd(double mid){
    memset(last,0,sizeof(last));t=1;
    for(int i=1;i<=m;++i){
        add(n+i,qq[i].from,inf);
        add(n+i,qq[i].to,inf);
        add(S,n+i,1.0);
    }
    for(int i=1;i<=n;++i){
        add(i,T,mid);
    }
    double pp,res=0;
    while(bfs()){
        while(pp=dfs(S,inf))res+=pp;
    }
    //cout<<res<<' '<<m<<endl;
    return (double(m)-res)>0;
}
void dfs1(int x){
    vis[x]=1;
    if(x>=1&&x<=n)cnt++;
    for(int i=last[x];i;i=e[i].nxt){
        int v=e[i].to;
        if(e[i].f&&!vis[v])dfs1(v);
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;++i){
        scanf("%d%d",&qq[i].from,&qq[i].to);
    }
    if(!m){puts("1");puts("1");return 0;}
    l=0,r=m+1;S=n+m+1,T=n+m+2;
    while(r-l>=1.0/n/n){
        //cout<<l<<' '<<r<<endl;
        mid=(l+r)/2;
        if(pd(mid))l=mid;
        else r=mid;
    }
    pd(l);
    dfs1(S);
    printf("%d\n",cnt);
    for(int i=1;i<=n;++i){
        if(vis[i])
        printf("%d\n",i);
    }
    //system("pause");
    return 0;
}

 

posted on 2018-01-25 14:09  湮灭之瞳  阅读(152)  评论(0编辑  收藏  举报