• 0x6A 网络流初步


    CH Round #17-C

    这个算是一个技能点吧,不点不会,点了就没什么了。懒得写看书吧书上的1应该是0。。。

    我又回来了太懒了不想翻书还是写写吧

    必须边的判定条件:该边流量为0且两端的点在残余网络不在同一个联通分量

    可行边的判定条件:该边流量为0或两端的点在残余网络在同一个联通分量

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int inf=(1<<30);
    
    struct node
    {
        int x,y,c,id,next,other;
    }a[2100000];int len,last[110000];
    void ins(int x,int y,int c,int id)
    {
        int k1,k2;
        
        len++;k1=len;
        a[len].x=x;a[len].y=y;a[len].c=c;a[len].id=id;
        a[len].next=last[x];last[x]=len;
        
        len++;k2=len;
        a[len].x=y;a[len].y=x;a[len].c=0;a[len].id=-1;
        a[len].next=last[y];last[y]=len;
        
        a[k1].other=k2;
        a[k2].other=k1;
    }
    int st,ed;
    int h[110000],list[110000];
    bool bt_h()
    {
        int head=1,tail=2;list[1]=st;
        memset(h,0,sizeof(h));h[st]=1;
        while(head!=tail)
        {
            int x=list[head];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(h[y]==0&&a[k].c>0)
                {
                    h[y]=h[x]+1;
                    list[tail++]=y;
                }
            }
            head++;
        }
        if(h[ed]==0)return false;
        return true;
    }
    int findflow(int x,int f)
    {
        if(x==ed)return f;
        int s=0;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(a[k].c>0&&h[y]==h[x]+1&&f>s)
            {
                int t=findflow(y,min(a[k].c,f-s));
                s+=t;a[k].c-=t;a[a[k].other].c+=t;
            }
        }
        if(s==0)h[x]=0;
        return s;
    }
    
    //------------------dicnic----------------------
    
    bool b[2100000];
    struct enode
    {
        int x,y,id,next;
    }e[2100000];int elen,elast[110000];
    void eins(int x,int y,int id)
    {
        elen++;
        e[elen].x=x;e[elen].y=y;e[elen].id=id;
        e[elen].next=elast[x];elast[x]=elen;
    }
    int z,dfn[110000],low[110000];
    int top,sta[110000];bool v[110000];
    int cnt,bel[110000];
    void SCC(int x)
    {
        dfn[x]=low[x]=++z;
        sta[++top]=x;v[x]=true;
        for(int k=elast[x];k;k=e[k].next)
        {
            int y=e[k].y;
            if(dfn[y]==0)
            {
                SCC(y);
                low[x]=min(low[x],low[y]);
            }
            else if(v[y]==true)
                low[x]=min(low[x],dfn[y]);
        }
        if(dfn[x]==low[x])
        {
            int k;cnt++;
            do
            {
                k=sta[top];top--;
                v[k]=false;
                bel[k]=cnt;
            }while(k!=x);
        }
    }
    
    int aslen,as[2100000];
    int main()
    {
        int n,m,T,x,y;
        scanf("%d%d%d",&n,&m,&T);
        st=n+m+1,ed=n+m+2;
        len=0;memset(last,0,sizeof(last));
        for(int i=1;i<=T;i++)
            scanf("%d%d",&x,&y), ins(x,y+n,1,i);
        for(int i=1;i<=n;i++)ins(st,i,1,-1);
        for(int i=1;i<=m;i++)ins(i+n,ed,1,-1);
        
        int ans=0;
        while(bt_h())
        {
            ans+=findflow(st,inf);
        }
        
        //-----------------------------------------
        
        elen=0;memset(elast,0,sizeof(elast));
        memset(b,true,sizeof(b));
        for(int i=1;i<=len;i++)
        {
            if(a[i].c==0&&a[i].y>n&&a[i].x!=st&&a[i].y!=ed)b[a[i].id]=false;
            if(a[i].c==1)
                eins(a[i].x,a[i].y,a[i].id);
        }
        
        z=0,top=0,cnt=0;
        for(int i=1;i<=n+m+2;i++)
            if(dfn[i]==0)SCC(i);
        
        for(int i=1;i<=elen;i++)
            if(bel[e[i].x]==bel[e[i].y])b[e[i].id]=false;
            
        aslen=0;
        for(int i=1;i<=T;i++)
            if(b[i]==true)as[++aslen]=i;
        printf("%d
    ",aslen);
        for(int i=1;i<aslen;i++)printf("%d ",as[i]);
        if(aslen!=0)printf("%d
    ",as[aslen]);
        return 0;
    }
    舞动的夜晚

    poj1966 不难。拆点,删除一个点相当于把他的两个点之间的边割掉。有趣的是,这题枚举起始点和结束点,意在把这两个点分在不同的集合,使得图不联通。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int inf=(1<<30);
    
    struct node
    {
        int x,y,c,next,other;
    }a[41000],e[41000];int len,last[110],elen,elast[110];
    void ins(int x,int y,int c)
    {
        int k1,k2;
        
        len++;k1=len;
        a[len].x=x;a[len].y=y;a[len].c=c;
        a[len].next=last[x];last[x]=len;
        
        len++;k2=len;
        a[len].x=y;a[len].y=x;a[len].c=0;
        a[len].next=last[y];last[y]=len;
        
        a[k1].other=k2;
        a[k2].other=k1;
    }
    int st,ed;
    int h[110],list[110];
    bool bt_h()
    {
        int head=1,tail=2;list[1]=st;
        memset(h,0,sizeof(h));h[st]=1;
        while(head!=tail)
        {
            int x=list[head];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(h[y]==0&&a[k].c>0)
                {
                    h[y]=h[x]+1;
                    list[tail++]=y;
                }
            }
            head++;
        }
        if(h[ed]==0)return false;
        return true;
    }
    int findflow(int x,int f)
    {
        if(x==ed)return f;
        int s=0;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(a[k].c>0&&h[y]==h[x]+1&&f>s)
            {
                int t=findflow(y,min(a[k].c,f-s));
                s+=t;a[k].c-=t;a[a[k].other].c+=t;
            }
        }
        if(s==0)h[x]=0;
        return s;
    }
    
    char ch;
    void sc(int &x,int &y)
    {
        ch=getchar();
        while(ch!='(')ch=getchar();
        scanf("%d",&x);x++;
        ch=getchar();
        while(ch!=',')ch=getchar();
        scanf("%d",&y);y++;
        ch=getchar();
        while(ch!=')')ch=getchar();
    }
    int main()
    {
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {        
            len=0;memset(last,0,sizeof(last));
            for(int i=1;i<=n;i++)ins(i,i+n,1);
            for(int i=1;i<=m;i++)
            {
                int x,y;sc(x,y);
                ins(x+n,y,inf);ins(y+n,x,inf);
            }
            
            memcpy(e,a,sizeof(e));
            elen=len;memcpy(elast,last,sizeof(elast));
            int mmin=inf;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(i!=j)
                    {
                        memcpy(a,e,sizeof(a));
                        len=elen;memcpy(last,elast,sizeof(last));
                        
                        st=i+n,ed=j;
                        int ans=0;
                        while(bt_h())
                        {
                            ans+=findflow(st,inf);
                        }
                        mmin=min(ans,mmin);
                    }
            if(mmin==inf)printf("%d
    ",n);
            else printf("%d
    ",mmin);
        }
        return 0;
    }
    poj1966

    poj3422 算是套路题吧,拆点后对于一个点的自连,连一条流量为1,费用为点权的边,连一条流量为K-1,费用为0的边。开始我从1,1的出边为起始到n,n的入边,问题在于无法控制只跑K次。天真的我还写了while(K--&&spfa())事实证明这样错得一批

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int inf=(1<<30);
    
    struct node
    {
        int x,y,c,d,next,other;
    }a[2100000];int len,last[11000];
    void ins(int x,int y,int c,int d)
    {
        int k1,k2;
        
        len++;k1=len;
        a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
        a[len].next=last[x];last[x]=len;
        
        len++;k2=len;
        a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
        a[len].next=last[y];last[y]=len;
        
        a[k1].other=k2;
        a[k2].other=k1;
    }
    int ans,st,ed;
    int list[11000],d[11000],pre[11000],c[11000];
    bool v[11000];
    bool spfa()
    {
        memset(d,63,sizeof(d));d[st]=0;
        memset(v,false,sizeof(v));v[st]=true;
        int head=1,tail=2;list[1]=st;c[st]=inf;
        while(head!=tail)
        {
            int x=list[head];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(a[k].c>0&&d[y]>d[x]+a[k].d)
                {
                    d[y]=d[x]+a[k].d;
                    pre[y]=k;
                    c[y]=min(a[k].c,c[x]);
                    if(v[y]==false)
                    {
                        v[y]=true;
                        list[tail++]=y;
                        if(tail==10500)tail=1;
                    }
                }
            }
            v[x]=false;
            head++;if(head==10500)head=1;
        }
        if(d[ed]==d[0])return false;
        else
        {
            ans+=d[ed]*c[ed];
            int y=ed;
            while(y!=st)
            {
                int k=pre[y];
                a[k].c-=c[ed];
                a[a[k].other].c+=c[ed];
                y=a[k].x;
            }
            return true;
        }
    }
    
    int n,mp[110][110];
    int pt(int x,int y){return n*(x-1)+y;}
    int main()
    {
        int K;
        scanf("%d%d",&n,&K);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&mp[i][j]);
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(i!=n)ins(n*n+pt(i,j),pt(i+1,j),K,0);
                if(j!=n)ins(n*n+pt(i,j),pt(i,j+1),K,0);
                ins(pt(i,j),n*n+pt(i,j),1,-mp[i][j]);
                ins(pt(i,j),n*n+pt(i,j),K-1,0);
            }
        st=pt(1,1);ed=n*n+pt(n,n);
        ans=0;
        while(spfa()==true);
        printf("%d
    ",-ans);
        return 0;
    }
    poj3422
  • 相关阅读:
    小团队Git协作管理
    android用MediaCodeC将opengl绘制内容录制为一个mp4
    非对称加密算法RSA 学习
    .obj 和 .mtl格式详解
    “m3u8格式简析”与“视频秒开优化”
    Jenkins Android打包(Mac平台)
    java引用Arcface,实现人脸识别(demo)
    ArcFace Demo [Android]
    C# ArcFace 免费人脸识别 2.0 demo
    [Windows][C#][.NET][WPF]基于ArcFace2.0+红外双目摄像头的活体检测
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/9544890.html
Copyright © 2020-2023  润新知