2019 HL SC day2

  今天讲的是网络流 大部分题目都写过了 这里 就总结一番。

bzoj 1066 裸的最大流 不过需要拆点细节方面有一点坑 剩下的 没什么了。

 //#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define ll long long
#define INF 1000000000
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft)?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=150010,maxn=30;
int n,m,h,t,S,T,c,maxflow,cnt,num,len=1;
int q[MAXN],vis[MAXN];
char a[maxn][maxn],b[maxn][maxn];
int pos[maxn][maxn],dis[maxn][maxn];
int lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN];
int dx[5]={0,0,0,1,-1};
int dy[5]={0,1,-1,0,0};
inline void add(int x,int y,int z)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline void bfs(int x,int y)
{
    memset(dis,0,sizeof(dis));
    h=t=0;q[++t]=x;vis[t]=y;
    //cout<<x<<' '<<y<<endl;
    while(h++<t)
    {
        for(int i=1;i<=4;++i)
        {
            int xx=q[h]+dx[i];
            int yy=vis[h]+dy[i];
            if(xx<0||yy<0||xx>n||yy>m)continue;
            if(xx==x&&yy==y)continue;
            if(dis[xx][yy])continue;
            dis[xx][yy]=dis[q[h]][vis[h]]+1;
            if(dis[xx][yy]>c)continue;
            if(a[xx][yy]!='0')add(pos[x][y]+num,pos[xx][yy],INF);
            q[++t]=xx;vis[t]=yy;
        }
    }
    if(min(x,y)<=c||min((n-x+1),(m-y+1))<=c)
    {
        //cout<<x<<' '<<y<<endl;
        add(pos[x][y]+num,T,INF);
    }
}
inline int bfs()
{
    memset(vis,0,sizeof(vis));
    h=t=0;q[++t]=S;vis[S]=1;
    while(h++<t)
    {
        int x=q[h];
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(!e[i]||vis[tn])continue;
            vis[tn]=vis[x]+1;
            q[++t]=tn;
            if(tn==T)return 1;
        }
    }
    return 0;
}
inline int dinic(int x,int flow)
{
    if(x==T)return flow;
    int rest=flow,k;
    for(int i=lin[x];i&&rest;i=nex[i])
    {
        int tn=ver[i];
        if(e[i]&&vis[tn]==vis[x]+1)
        {
            k=dinic(tn,min(e[i],rest));
            if(!k)vis[tn]=0;
            e[i]-=k;e[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();c=read();
    for(int i=1;i<=n;++i)scanf("%s",a[i]+1);
    for(int i=1;i<=n;++i)scanf("%s",b[i]+1);
    S=n*m*3+1;T=S+1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            pos[i][j]=++num;
            if(b[i][j]!='L')continue;
            ++cnt;add(S,cnt+n*m*2,1);
            add(cnt+n*m*2,pos[i][j],1);
        }
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)
            if(a[i][j]!='0')
            {
                add(pos[i][j],pos[i][j]+num,a[i][j]-'0');
                bfs(i,j);
            }
    }
    int flow=0;while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
    printf("%d
",cnt-maxflow);
    return 0;
}
View Code

bzoj 3993 最大流 需要二分一下答案 然后最大流分配攻击 看能否全部攻击。有点小卡精度 需要*10000 实数上二分较好。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define RE register
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    RE int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=55,maxn=100010;
int n,m,len=1,S,T,h,t;
int c[MAXN][MAXN],flag[MAXN];
int lin[maxn],nex[maxn],ver[maxn],vis[maxn],q[maxn];
ll e[maxn],a[MAXN],b[MAXN],ti,sum;
inline void add(int x,int y,ll z)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline int bfs()
{
    memset(vis,0,sizeof(vis));
    h=t=0;q[++t]=S;vis[S]=1;
    while(h++<t)
    {
        int x=q[h];
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(!e[i]||vis[tn])continue;
            vis[tn]=vis[x]+1;
            q[++t]=tn;
            if(tn==T)return 1;
        }
    }
    return 0;
}
inline ll dinic(int x,ll flow)
{
    if(x==T)return flow;
    ll rest=flow,k;
    for(int i=lin[x];i&&rest;i=nex[i])
    {
        int tn=ver[i];
        if(e[i]&&vis[tn]==vis[x]+1)
        {
            k=dinic(tn,min(e[i],rest));
            if(!k)vis[tn]=0;
            e[i]-=k;e[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
inline int check()
{
    ll flow=0,maxflow=0;
    while(bfs())while((flow=dinic(S,INF*10000ll)))maxflow+=flow;
    return maxflow==sum;
}
inline void build(ll x)
{
    len=1;memset(lin,0,sizeof(lin));
    for(int i=1;i<=m;++i)add(S,i,x*b[i]);
    for(int i=1;i<=n;++i)add(i+m,T,a[i]);
    for(int i=1;i<=m;++i)
        for(int j=1;j<=n;++j)
            if(c[i][j])add(i,j+m,INF*10000ll);
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    S=n+m+1;T=S+1;
    for(int i=1;i<=n;++i)a[i]=read()*10000ll,sum+=a[i];
    for(int i=1;i<=m;++i)b[i]=read();
    for(int i=1;i<=m;++i)
        for(int j=1;j<=n;++j)
        {
            c[i][j]=read();
            if(c[i][j]&&!flag[j])ti+=a[j],flag[j]=1;
        }
    ll l=0,r=ti;
    while(l+1<r)
    {
        ll mid=(l+r)>>1;
        build(mid);
        if(check())r=mid;
        else l=mid;
    }
    build(l);
    if(check())printf("%.4lf",(double)l/10000.0);
    else printf("%.4lf",(double)r/10000.0);
    return 0;
}
View Code

luogu 4126 很难的最小割问题。竟然还需要tarjan 。。我有点蠢迷了将近20min 才发现一些性质被我完美的忽略掉了。

1 跑一边最大流 不满流的边一定不会属于割集 显然 我们将其割掉 那么再割掉其他边 那么最小割将>最大流故 不满流的边一定不会属于割集

2 满流的边有可能属于 割集 有可能也不属于割集 因为存在 流光往一处流的可能。。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define RE register
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    RE int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=4010,maxn=60010<<1;
int n,m,len=1,S,T,maxflow,t,h,num,cnt,top;
int q[MAXN],vis[MAXN],dfn[MAXN],low[MAXN],c[MAXN],s[MAXN];
int lin[MAXN],nex[maxn],ver[maxn],e[maxn];
inline void add(int x,int y,int z)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
struct wy
{
    int x,y,id;
}w[maxn];
inline int bfs()
{
    memset(vis,0,sizeof(vis));
    h=t=0;q[++t]=S;vis[S]=1;
    while(h++<t)
    {
        int x=q[h];
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(!e[i]||vis[tn])continue;
            q[++t]=tn;vis[tn]=vis[x]+1;
            if(tn==T)return 1;
        }
    }
    return 0;
}
inline int dinic(int x,int flow)
{
    if(x==T)return flow;
    int rest=flow,k;
    for(int i=lin[x];i&&rest;i=nex[i])
    {
        int tn=ver[i];
        if(vis[tn]==vis[x]+1&&e[i])
        {
            k=dinic(tn,min(e[i],rest));
            if(!k){vis[tn]=0;continue;}
            e[i]-=k;e[i^1]+=k;rest-=k;
        }
    }
    return flow-rest;
}
inline void tarjan(int x)
{
    dfn[x]=low[x]=++num;
    s[++top]=x;vis[x]=1;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(e[i]==0)continue;
        if(!dfn[tn])
        {
            tarjan(tn);
            low[x]=min(low[x],low[tn]);
        }
        else if(vis[tn])low[x]=min(low[x],dfn[tn]);
    }
    if(dfn[x]==low[x])
    {
        ++cnt;int y;
        do
        {
            y=s[top--];
            vis[y]=0;
            c[y]=cnt;
        }while(x!=y);
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();S=read();T=read();
    for(int i=1;i<=m;++i)
    {
        int x,y,z;
        x=read();y=read();z=read();
        add(x,y,z);
        w[i]=(wy){x,y,len-1};
    }
    int flow=0;
    while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
    //printf("%d
",maxflow);
    //problem 1:是否存在一个最小割的切断方案该道路属于割集
    //problem 2:当前路径是否在任意一个割集中都存在
    //对于问题2 显然的是如果一定是割集的话意味着流入量比当前容量大 可流出量也比当前容量大+1则增大流量
    //那么这条边的左端点一定是和S属于同一个强连通分量之中 右端点和T在同一个强联通分量当中
    //对于问题1 显然暴力可以判断 当然两端如果还能互相到达 那么一定不会属于割集 
    //证明:设这条边左断点为u 右端点为v 且当前满流 v通过反向边一定可以到u u能到v当且仅当从u出发能到T
    //故切掉这条边还有流能到T 若此边属于此割集 就一定不存在这样的流 所以假设不成立。
    //得证。
    for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i);
    for(int i=1;i<=m;++i)
    {
        if(e[w[i].id])printf("%d %d
",0,0);
        else 
        {
            if(c[w[i].x]!=c[w[i].y])
            {
                printf("%d ",1);
                //cout<<c[w[i].x]<<' '<<c[S]<<endl;
                //cout<<c[w[i].y]<<' '<<c[T]<<endl;
                if(c[w[i].x]==c[S]&&c[w[i].y]==c[T])printf("%d
",1);
                else printf("%d
",0);
            }
            else printf("%d %d
",0,0);
        }
    }
    return 0;
}
View Code

具体怎么写见代码注释。

bzoj 3894 文理分科 最小割裸题 虚建几个点即可。

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db double
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
inline void put(int x)
{
    x<0?x=-x,putchar('-'):0;
    int num=0;char ch[20];
    while(x)ch[++num]=x%10+'0',x/=10;
    num==0?putchar('0'):0;
    while(num)putchar(ch[num--]);
    putchar('
');return;
}
const int MAXN=110,maxn=400010;
int n,m,len=1,maxflow,S,T,t,h,sum,cnt;
int pos[MAXN][MAXN];
int vis[maxn],q[maxn];
int lin[maxn],ver[maxn],nex[maxn],e[maxn];
const int dx[5]={0,0,0,1,-1};
const int dy[5]={0,1,-1,0,0};
inline void add(int x,int y,int z)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline int bfs()
{
    memset(vis,0,sizeof(vis));
    h=t=0;q[++t]=S;vis[S]=1;
    while(h++<t)
    {
        int x=q[h];
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(!e[i]||vis[tn])continue;
            vis[tn]=vis[x]+1;
            q[++t]=tn;
            if(tn==T)return 1;
        }
    }
    return 0;
}
inline int dinic(int x,int flow)
{
    if(x==T)return flow;
    int rest=flow,k;
    for(int i=lin[x];i&&rest;i=nex[i])
    {
        int tn=ver[i];
        if(e[i]&&vis[tn]==vis[x]+1)
        {
            k=dinic(tn,min(e[i],rest));
            if(!k)vis[tn]=0;
            e[i]-=k;e[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    S=n*m+1;T=S+1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            int x;
            x=read();sum+=x;
            pos[i][j]=++cnt;
            add(S,pos[i][j],x);
        }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            int x=read();sum+=x;
            add(pos[i][j],T,x);
        }
    cnt=T;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            int x=read();
            add(S,++cnt,x);sum+=x;
            for(int k=0;k<5;++k)
            {
                int xx=i+dx[k];
                int yy=j+dy[k];
                if(pos[xx][yy])add(cnt,pos[xx][yy],INF);
            }
        }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            int x=read();
            add(++cnt,T,x);sum+=x;
            for(int k=0;k<5;++k)
            {
                int xx=i+dx[k];
                int yy=j+dy[k];
                if(pos[xx][yy])add(pos[xx][yy],cnt,INF);
            }
        }
    int flow=0;while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
    printf("%d
",sum-maxflow);
    return 0;
}
View Code

luogu 3749 最大权闭合子图 我很迷的写完了。

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db double
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
inline void put(int x)
{
    x<0?x=-x,putchar('-'):0;
    int num=0;char ch[20];
    while(x)ch[++num]=x%10+'0',x/=10;
    num==0?putchar('0'):0;
    while(num)putchar(ch[num--]);
    putchar('
');return;
}
const int MAXN=110,maxn=MAXN*MAXN<<3;
int n,m,cnt,t,h,S,T,maxflow,sum,len=1;
int a[MAXN][MAXN],pos[MAXN][MAXN];
int b[MAXN],vis[maxn],q[maxn];
int lin[maxn],ver[maxn],nex[maxn],e[maxn];
inline void add(int x,int y,int z)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline int bfs()
{
    memset(vis,0,sizeof(vis));
    h=t=0;q[++t]=S;vis[S]=1;
    while(h++<t)
    {
        int x=q[h];
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(!e[i]||vis[tn])continue;
            q[++t]=tn;vis[tn]=vis[x]+1;
            if(tn==T)return 1;
        }
    }
    return 0;
}
inline int dinic(int x,int flow)
{
    if(x==T)return flow;
    int rest=flow,k;
    for(int i=lin[x];i&&rest;i=nex[i])
    {
        int tn=ver[i];
        if(vis[tn]==vis[x]+1&&e[i])
        {
            k=dinic(tn,min(e[i],rest));
            if(!k){vis[tn]=0;continue;}
            e[i]-=k;e[i^1]+=k;rest-=k;
        }
    }
    return flow-rest;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;++i)b[i]=read();
    for(int i=1;i<=n;++i)
        for(int j=i;j<=n;++j)a[i][j]=read(),pos[i][j]=++cnt;
    S=cnt+1;T=S+1;cnt=T;
    for(int i=1;i<=n;++i)
        for(int j=i;j<=n;++j)
        {
            if(i==j)
            {
                a[i][j]-=b[i];
                if(a[i][j]<0)add(pos[i][j],T,-a[i][j]);
                else add(S,pos[i][j],a[i][j]),sum+=a[i][j];
                continue;
            }
            if(a[i][j]<0)
            {
                add(pos[i][j],T,-a[i][j]);
                add(pos[i][j],pos[i+1][j],INF);
                add(pos[i][j],pos[i][j-1],INF);
            }
            else
            {
                sum+=a[i][j];
                add(S,pos[i][j],a[i][j]);
                add(pos[i][j],pos[i+1][j],INF);
                add(pos[i][j],pos[i][j-1],INF);
            }
        }
    for(int i=1;i<=n;++i)
    {
        if(!vis[b[i]])
        {
            vis[b[i]]=++cnt;
            add(vis[b[i]],T,m*b[i]*b[i]);
        }
        add(pos[i][i],vis[b[i]],INF);
        //cout<<pos[i][i]<<' '<<vis[b[i]]<<endl;
    }
    int flow=0;
    while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
    printf("%d
",max(0,sum-maxflow));
    return 0;
}
View Code

迷的地方在这里 如果一个组合权值为负 那么是这样连边:

而并非这样:

理由是 我选择了 l r 必须选择 l+1,r 和 r-1,l 这是必要的 第二种连边体现不出来这个特点故是错误的。

最大密度子图 01分数规划后转 最大权闭合子图即可。

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db long double
#define EPS 1e-8
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
inline void put(int x)
{
    x<0?x=-x,putchar('-'):0;
    int num=0;char ch[20];
    while(x)ch[++num]=x%10+'0',x/=10;
    num==0?putchar('0'):0;
    while(num)putchar(ch[num--]);
    putchar('
');return;
}
const int MAXN=110,maxn=1100*50;
int n,m,S,T,ans,t,h,len=1;
struct wy
{
    int x,y;
}s[maxn];
int vis[maxn],q[maxn];
int lin[maxn],ver[maxn],nex[maxn];
db e[maxn];
inline void add(int x,int y,db z)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline int bfs()
{
    memset(vis,0,sizeof(vis));
    t=h=0;q[++t]=S;vis[S]=1;
    while(h++<t)
    {
        int x=q[h];
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(vis[tn])continue;
            if(e[i]<=EPS)continue;
            q[++t]=tn;vis[tn]=vis[x]+1;
            if(tn==T)return 1;
        }
    }
    return 0;
}
inline db dfs(int x,db flow)
{
    if(x==T)return flow;
    db rest=flow,k;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(rest<=EPS)continue;
        if(vis[tn]==vis[x]+1)
        {
            if(e[i]<=EPS)continue;
            k=dfs(tn,min(e[i],rest));
            if(k<=EPS)vis[tn]=0;
            e[i]-=k;e[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
inline db dinic()
{
    db flow=0,maxflow=0;
    while(bfs())while((flow=dfs(S,INF)))maxflow+=flow;
    return maxflow;
}
inline db check(db w)
{
    len=1;
    memset(lin,0,sizeof(lin));
    for(int i=1;i<=m;++i)add(S,i,1),add(i,s[i].x+m,INF),add(i,s[i].y+m,INF);
    for(int i=1;i<=n;++i)add(i+m,T,w);
    return (db)m-dinic();
}
inline void dfs(int x)
{
    vis[x]=1;
    if(x>m&&x<=n+m)++ans;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(e[i]>EPS&&!vis[tn])dfs(tn);
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    if(!m){puts("1");return 0;}
    S=n+m+1;T=S+1;
    for(int i=1;i<=m;++i)    
    {
        int x,y;
        x=read();y=read();
        s[i]=(wy){x,y};
    }
    db l=0.49,r=(db)m/2.0,eps=(1.0/n)/n;
    while(l+eps<r)
    {
        db mid=(l+r)*0.5;
        if(check(mid)>EPS)l=mid;
        else r=mid;
    }
    check(l);
    memset(vis,0,sizeof(vis));
    dfs(S);
    printf("%d
",ans);
    return 0;
}
View Code

费用流:

bzoj4514 还算比较简单 搞成二分图 注意快速连边的方法即可。

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 100000000000000000ll
#define inf 1000000000
#define ll long long
#define min(x,y) (x>y?y:x)
#define max(x,y) (x>y?x:y)
#define RI register long long
#define up(p,i,n) for(int i=p;i<=n;++i)
#define db double
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
//啊 自闭了 写发SDOI找回自信。。
//SDOI 2016 数字配对。
//一个数字是ai 有bi个 权值是ci
//当且仅当ai/aj是质数 两个数字可以配对 显然是最大费用最大流!
//考虑如何建图 显然的是这是一张二分图建一张即可。注意开ll
const int MAXN=210*210;
int n,len=1,h,t,T,S;
int a[MAXN],b[MAXN],w[MAXN],in[MAXN];
int q[MAXN],pre[MAXN],vis[MAXN],f[MAXN];
ll dis[MAXN],sum,e1[MAXN<<1],maxflow,c[MAXN];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1];
inline void add(int x,int y,int z,ll z1)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;e1[len]=z1;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;e1[len]=-z1;
}
inline void transform(int x)
{
    int w=a[x],cnt=0;
    for(int i=2;i*i<=a[x];++i)
        while(w%i==0)
        {
            w/=i;
            ++cnt;
        }
    if(w>1)++cnt;
    f[x]=cnt;
}
inline int spfa()//最大费用最大流
{
    for(int i=1;i<=T;++i)dis[i]=-INF;
    t=h=0;dis[S]=0;q[++t]=S;vis[S]=1;in[S]=inf;
    while(h++<t)
    {
        int x=q[h];vis[x]=0;
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(!e[i])continue;
            if(dis[tn]<dis[x]+e1[i])
            {
                dis[tn]=dis[x]+e1[i];
                in[tn]=min(in[x],e[i]);
                pre[tn]=i;
                if(!vis[tn])q[++t]=tn,vis[tn]=1;
            }
        }
    }
    return dis[T]!=-INF;
}
inline void EK()
{
    while(spfa())
    {
        int x=T,i=pre[x];
        if(sum+in[T]*dis[T]<0)
        {
            maxflow+=sum/(-dis[T]);
            break;
        }
        sum+=in[T]*dis[T];
        maxflow+=in[T];
        while(x!=S)
        {
            e[i]-=in[T];
            e[i^1]+=in[T];
            x=ver[i^1];i=pre[x];
        }
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();S=n+1;T=S+1;
    for(int i=1;i<=n;++i)a[i]=read(),transform(i);
    for(int i=1;i<=n;++i)b[i]=read();
    for(int i=1;i<=n;++i)c[i]=read();
    for(int i=1;i<=n;++i)
        if(f[i]&1)for(int j=1;j<=n;++j)
            if(((f[i]==f[j]+1)&&(a[i]%a[j]==0))||((f[i]==f[j]-1&&a[j]%a[i]==0)))
                add(i,j,inf,c[i]*c[j]);
    for(int i=1;i<=n;++i)
        if(f[i]&1)add(S,i,b[i],0);
        else add(i,T,b[i],0);
    EK();
    printf("%lld
",maxflow);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/chdy/p/11149079.html