• 网络流24题!!!!


    网1:飞行员匹配

    题目链接:https://www.oj.swust.edu.cn/problem/show/1736

    俩种做法:

    /**********二分图匹配做法***********/
    #include<bits/stdc++.h>
    using namespace std;
    const int M=102;
    int n,m;
    int e[M][M],match[M],used[M];
    bool find(int u){
        for(int i=1;i<=m;i++){
            if(e[u][i]==1&&used[i]==0){
                used[i]=1;
                if(match[i]==0||find(match[i])){
                    match[i]=u;
                    return true;
                }
            }
        }
        return false;
    }
    int main(){
        scanf("%d%d",&m,&n);
        int x,y;
        while(~scanf("%d%d",&x,&y)){
            if(x==-1&&y==-1)
                break;
             
            e[x][y]=1;
            e[y][x]=1;
        }
    //  if(m==n||m==0)
             
        int ans=0;
        for(int i=m+1;i<=n;i++){
            memset(used,0,sizeof(used));
            if(find(i))
                ans++;
        }
        if(ans==0)
            return puts("No Solution!"),0;
        printf("%d
    ",ans);
        for(int i=1;i<=m;i++)
            if(match[i])
                printf("%d %d
    ",i,match[i]);
        return 0;
    }
    /***************网络流**************/
    #include<bits/stdc++.h>
    using namespace std;
    const int M=505;
    int cur[M],deep[M],head[M],s,t,tot;
    const int inf=0x3f3f3f3f;
    struct node{
        int v,nextt,w;
    }e[M*50];
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    bool bfs(){
        memset(deep,0,sizeof(deep));
        queue<int>que;
        que.push(s);
        deep[s]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];i!=-1;i=e[i].nextt){
                int v=e[i].v;
                if(e[i].w>0&&deep[v]==0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;
                    que.push(v);
                }
            }
        }
        return deep[t]==0?false:true;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int x=0,ans=0;
        for(int i=cur[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(deep[u]+1==deep[v]&&e[i].w>0){
                x=dfs(v,min(fl-ans,e[i].w));
                e[i].w-=x;
                e[i^1].w+=x;
                if(e[i].w)
                    cur[u]=i;
                ans+=x;
                if(ans==fl)
                    return fl;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=t;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    int main(){
        memset(head,-1,sizeof(head));
        int n,m;
        cin>>m>>n;
        s=0,t=n+1;
        for(int i=1;i<=m;i++){
            addedge(s,i,1);
        }
        for(int i=m+1;i<=n;i++){
            addedge(i,t,1);
        }
        int x,y;
        while(~scanf("%d%d",&x,&y)){
            if(x==-1&&y==-1)
                break;
            addedge(x,y,1);
        }
        int ans=dinic(t);
        if(ans==0)
            return puts("No Solution!"),0;
        printf("%d
    ",ans);
        for(int i=m+1;i<=n;i++)
            for(int j=head[i];j!=-1;j=e[j].nextt)
                if(e[j].v!=t&&e[j].w==1)
                    printf("%d %d
    ",e[j].v,i);
        return 0;
    }
    View Code

    网2:飞行员计划问题

    题目链接:https://www.oj.swust.edu.cn/problem/show/1737

    最大权闭合图(总的答案就是最小路径覆盖的答案)

    从起点往每个权值为正的点建立一条边,容量为点权值。

    每个权值为负的点往终点建立一条边,容量为权值的绝对值。

    如果选A就必须选B 则就从A建立一条往B的边,容量为inf。

    最大权闭合图的点就是从起点开始广搜,权值为0的点不走,能走到的点就是被选中的点。

    dinic最后一次bfs的d数组正好可以用来判断这个条件。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=505;
    const int inf=0x3f3f3f3f;
    struct node{
        int v,w,nextt;
    }e[M*50];
    int head[M],cur[M],deep[M],s,t,tot;
    bool bfs(){
        memset(deep,0,sizeof(deep));
        queue<int >que;
        que.push(s);
        deep[s]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];i!=-1;i=e[i].nextt){
                int v=e[i].v;
                if(e[i].w>0&&deep[v]==0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;;
                    que.push(v);
                }    
            }
        }
        return false;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0,x=0;
        for(int i=cur[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==deep[u]+1){
                x=dfs(v,min(e[i].w,fl-ans));
                e[i].w-=x;
                e[i^1].w+=x;
                if(e[i].w)
                    cur[u]=i;
                
                ans+=x;
                if(ans==fl)
                    return fl;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=n;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    void init(){
        memset(head,-1,sizeof(head));
        tot=0;
    }
    int main(){
        
        init();
        int m,n;
        cin>>m>>n;
        s=0,t=n+m+1;
        int sum=0;
        for(int i=1;i<=m;i++){
            int w;
            scanf("%d",&w);
            addedge(s,n+i,w);
            sum+=w;
            int x;
            char ch;
            while(true){
                scanf("%d%c",&x,&ch);
                addedge(n+i,x,inf);
                if(ch=='
    '||ch=='
    ')
                    break;
            }
        }
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            addedge(i,t,x);
        }
        sum-=dinic(t);
        
        for(int i=1;i<=m;i++){
            if(deep[n+i])
                printf("%d ",i);
        }
        putchar('
    ');
        for(int i=1;i<=n;i++){
            if(deep[i])
                printf("%d ",i);
        }
        putchar('
    ');
        
        
        
        
        
        printf("%d
    ",sum);
        return 0;
    }
    View Code

    3、最小路径覆盖问题

    题目链接:https://loj.ac/problem/6002

    最小路径覆盖问题模型,拆点做最大匹配,总点数减去最大流为需要的最少的边数

    题目有建图方法

    拆点意思是这样的,第i个点的流量流向第j个点时表示第i个点的下一个点是j点,剩下的没办法流向终点的点就是没有点能到它那里,说明这个点是边的起点,根据这个来递归可以用来查找答案方案。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=505; 
    const int inf=0x3f3f3f3f;
    struct node{
        int v,nextt,w;
    }e[M*50];
    int head[M],book[M],cur[M],deep[M],s,t,tot,n;
    inline int read(){
        int sum=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        return x?sum:-sum;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    bool bfs(){
        memset(deep,0,sizeof(deep));
        queue<int>que;
        que.push(s);
        deep[s]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];i!=-1;i=e[i].nextt){
                int v=e[i].v;
                if(e[i].w>0&&deep[v]==0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;
                    que.push(v);
                }
            }
        }
        return deep[t]==0?false:true;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0,x=0;
        for(int i=cur[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==deep[u]+1){
                x=dfs(v,min(e[i].w,fl-ans));
                e[i].w-=x;
                e[i^1].w+=x;
                if(e[i].w)
                    cur[u]=i;
                ans+=x;
                if(ans==fl)
                    return ans;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=n;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    void dfs2(int u,int &flag){
        int point=u+n;
        book[u]=1;
        for(int i=head[point];i!=-1;i=e[i].nextt){
            if(e[i].v!=t&&e[i].w==1){
                dfs2(e[i].v,flag);
            }
        }
        
        if(flag==1)
            flag=0;
        else
            putchar(' ');
        write(u);
    }
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    int main(){
        init();
        n=read();
        int m;
        m=read();
        s=0,t=(n<<1)+1;
        for(int i=1;i<=n;i++)
            addedge(s,i,1),addedge(i+n,t,1);
        while(m--){
            int x=read(),y=read();
            addedge(x,y+n,1);
        }
        int sum=n-dinic(t);
        for(int i=head[t];i!=-1;i=e[i].nextt){
            int flag=1;
            if(!book[e[i].v-n]&&e[i].w==1){
                dfs2(e[i].v-n,flag);
                puts("");
            }
        }
        for(int i=1;i<=n;i++)
            if(!book[i])
                write(i),putchar('
    ');
        write(sum);
        putchar('
    ');
        return 0;
    }
    View Code

    4、魔术球问题

    题目链接:https://www.oj.swust.edu.cn/problem/show/1739

    网络流跑形成的每条链就是题目要求的管子
    由此答案就是各个点形成网络流的最小路径覆盖

    因为网络流是在残量网络流上跑的,所以我们每次加一个点进去,在把符合条件的边加上去

    注意判断条件:for(i=1; i-ans<=n+1; i++)
    当加到刚好超过给点的n时即为答案,I是网络流上的点(除起点,汇点外),ans是最大流;

    然后输出方案那里/2的意思因为我每次建点都是健俩点,所以输出方案点数编号的时候对应的就是其1/2倍。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=11111;
    const int inf=0x3f3f3f3f;
    struct node
    {
        int v,nextt,w;
    }e[M*20];
    int head[M],cur[M],deep[M],hei[M],y[M],book[M],s,t,tot,cnt;
    
    inline int read(){
        int sum=0,sign=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                sign=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        return sign?sum:-sum;
    }
    inline void write(int f){
        if(f<0)
            putchar('-'),f=-f;
        if(f>9)
            write(f/10);
        putchar(f%10+'0');
    }
    bool bfs(){
        memset(deep,0,sizeof(deep));
        queue<int>que;
        que.push(s);
        deep[s]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];~i;i=e[i].nextt){
                int v=e[i].v;
                if(e[i].w>0&&deep[v]==0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;
                    que.push(v);
                }
            }
        }
        return deep[t]==0?false:true;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0,p=0;
        for(int i=cur[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==deep[u]+1&&e[i].w>0){
                p=dfs(v,min(fl-ans,e[i].w));
                e[i].w-=p;
                e[i^1].w+=p;
                if(e[i].w)
                    cur[u]=i;
                ans+=p;
                if(ans==fl)
                    return fl;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs())
        {
            for(int i=0;i<=n;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    void init(){
        memset(head,-1,sizeof(head));
        tot=0,cnt=2;
    }
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    void prin(int u2,int &flag){
        book[u2]=1;
        int u=y[u2];
        for(int i=head[u];~i;i=e[i].nextt){
            if(e[i].w==1&&e[i].v!=t)
                prin(e[i].v/2,flag);
        }
        if(flag)
            flag=0;
        else
            putchar(' ');
        write(u2);
    }
    int main(){
        init();
        int n=read();
        s=0,t=11110;
        int i,ans=0;
        for(i=1;i-ans<=n+1;i++){
            hei[i]=cnt++;
            y[i]=cnt++;
            addedge(s,hei[i],1);
            addedge(y[i],t,1);
            for(int j=1;j<i;j++){
                int l=sqrt(i+j);
                if(l*l==i+j){
                    addedge(hei[j],y[i],1);
                }
            }
            ans+=dinic(t);
        }
        int sum=i-2;
        write(sum);
        putchar('
    ');
        int flag=1;
        for(int i=head[t];~i;i=e[i].nextt){
            if(e[i].w==1&&!book[e[i].v/2]){
                flag=1;
                prin(e[i].v/2,flag);
                putchar('
    ');
            }
        }
        for(int i=1;i<=sum;i++)
            if(!book[i])
                write(i),putchar('
    ');
        return 0;
        
    }
    View Code

    5、圆桌问题

    题目链接:https://www.luogu.org/problemnew/show/P3254

    建图问题:健超级源点s,超级汇点t
    s向每个代表连一条边,容量为人数------1
    每个代表向每个圆桌拆个点出来连,容量为1(代表要一个人)-----2
    最后每个圆桌向超级汇点连边,容量为圆桌允许人数ci-----3
    第一步的编号为:1~n;
    第二步的编号为:n+1~n+n*m;
    第三步的编号为:n+n*m+1~n+n*m+m;
    所以t编号为n+n*m+m+1;
    跑网络流看最大流等不等与代表总人数


    然后就是输出方案:
    因为有走过,所以邻接边为1(看代码应该看得懂)
    输出答案的话就找那个限制流量的边,如果那个边走过了就说明这个点有用嘛,找一下输出就行。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=50005;
    const int inf=0x3f3f3f3f;
    struct node{
        int v,nextt,w;
    }e[M*20];
    int head[M],cur[M],deep[M],tot,s,t;
    inline int read(){
        int sum=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        return x?sum:-sum;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    bool bfs(){
        memset(deep,0,sizeof(deep));
        deep[s]=1;
        queue<int>que;
        que.push(s);
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];~i;i=e[i].nextt){
                int v=e[i].v;
                if(deep[v]==0&&e[i].w>0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;
                    que.push(v);
                }
            }
        }
        return deep[t]==0?false:true;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0,x=0;
        for(int i=cur[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==deep[u]+1){
                x=dfs(v,min(fl-ans,e[i].w));
                e[i].w-=x;
                e[i^1].w+=x;
                if(e[i].w)
                    cur[u]=i;
                ans+=x;
                if(ans==fl)
                    return ans;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=n;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    vector<int>a[M];
    int main(){
        init();
        int n=read(),m=read();
        s=0,t=n+n*m+m+1;
        int sum=0;
        for(int i=1;i<=n;i++){
            int x=read();
            sum+=x;
            addedge(s,i,x);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                addedge(i,n+(i-1)*m+j,1);
                addedge(n+(i-1)*m+j,n+n*m+j,1);
            }
        }
        for(int i=1;i<=m;i++){
            int x=read();
            addedge(n+n*m+i,t,x);
        }
        if(dinic(t)==sum){
            puts("1");
        }
        else
            return puts("0"),0;
        //cout<<"!!"<<endl;
        for(int i=1;i<=m;i++){
            for(int j=head[n+n*m+i];~j;j=e[j].nextt){
                if(e[j].v!=t&&e[j].w==1){
                    a[(e[j].v-n-i)/m+1].push_back(i);
                }
            }
        }
        for(int i=1;i<=n;i++){
            write(a[i][0]);
            for(int j=1;j<a[i].size();j++)
                putchar(' '),write(a[i][j]);
            putchar('
    ');
        }
        return 0;
    }
    View Code

    6、最长递增子序列问题

    题目链接:https://www.luogu.org/problemnew/show/P2766

    第一问就用nlogn的dp去做,然后第二问第三问就用dp过程来模拟走网络流过程,建图也是如此;


    将每个点拆点边权为1(代表只能用一次),然后其他看代码建图应该能懂;

    第三问特殊地要求x1和xn可以重复使用,只需取消这两个点相关边的流量限制,求网络最大流即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=805;
    const int  inf=0x3f3f3f3f;
    struct node{
        int v,nextt,w;
    }e[20005];
    int head[20005],cur[20005],deep[20005],s,t,tot,a[M],dp[M];
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    bool bfs(){
        memset(deep,0,sizeof(deep));
        queue<int>que;
        que.push(s);
        deep[s]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];~i;i=e[i].nextt){
                int v=e[i].v;
                if(deep[v]==0&&e[i].w>0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;
                    que.push(v);
                }
            }
        }
        return deep[t]==0?false:true;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int x=0,ans=0;
        for(int i=cur[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==deep[u]+1&&e[i].w>0){
                x=dfs(v,min(fl-ans,e[i].w));
                e[i].w-=x;
                e[i^1].w+=x;
                if(e[i].w)
                    cur[u]=i;
                ans+=x;
                if(ans==fl)
                    return ans;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=n;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    int main(){
        int n;
        scanf("%d",&n);
        s=0,t=n*2+1;
        init();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            dp[i]=1;
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<i;j++)
                if(a[i]>=a[j])
                    dp[i]=max(dp[j]+1,dp[i]);
        int ans=0;
        for(int i=1;i<=n;i++){
            ans=max(ans,dp[i]);
        }
        for(int i=1;i<=n;i++)
            if(dp[i]==ans)
                addedge(s,i,1);
                
        for(int i=1;i<=n;i++)
            addedge(i+n,i,1);
            
        for(int i=1;i<=n;i++)
            if(dp[i]==1)
                addedge(i,t,1);
                
        for(int i=1;i<=n;i++)
            for(int j=1;j<i;j++)
                if(a[i]>=a[j]&&dp[i]==dp[j]+1)
                    addedge(i,j+n,1);
        int c=dinic(t);
        printf("%d
    %d
    ",ans,c);    
        if(dp[n]==ans)
            addedge(s,n,inf);
        addedge(1+n,1,inf);
        addedge(1,t,inf);
        c+=dinic(t);
        printf("%d
    ",c);
        return 0;    
    }
    View Code

    7、试题库问题

    题目链接:https://www.luogu.org/problemnew/show/P2763

    ////把k个项目向汇点t连容量为ki的容量;
    把n个点拆点出来,容量为1(代表用一次)

    #include<bits/stdc++.h>
    using namespace std;
    const int M=5e+5;
    const int inf=0x3f3f3f3f;
    struct node{
        int v,w,nextt;
    }e[M<<1];
    int head[M],cur[M],deep[M],s,t,tot;
    bool bfs(){
        memset(deep,0,sizeof(deep));
        queue<int>que;
        deep[s]=1;
        que.push(s);
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];~i;i=e[i].nextt){
                int v=e[i].v;
                if(deep[v]==0&&e[i].w>0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;
                    que.push(v);
                }
            }
        }
        return deep[t]==0?false:true;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0,x=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==deep[u]+1&&e[i].w>0){
                x=dfs(v,min(fl-ans,e[i].w));
                e[i].w-=x;
                e[i^1].w+=x;
                if(e[i].w)
                    cur[u]=i;
                ans+=x;
                if(ans==fl)
                    return ans;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=n;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
    
        }
        return ans;
    }
    void init(){
        memset(head,-1,sizeof(head));
        tot=0;
        
    }
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    int main(){
        init();
        int k,n;
        scanf("%d%d",&k,&n);
        s=0,t=2*n+k+1;
        int sum=0;
        for(int i=1;i<=k;i++){
            int x;
            scanf("%d",&x);
            addedge(i,t,x);
            sum+=x;
        }
        for(int i=1;i<=n;i++)
            addedge(s,k+i,1);
        for(int i=1;i<=n;i++){
            int p;
            addedge(k+i,k+i+n,1);
            scanf("%d",&p);
            while(p--){
                int sign;
                scanf("%d",&sign);
                addedge(k+i+n,sign,1);
            }
        }
        if(dinic(t)!=sum)
            return puts("No Solution!"),0;
        for(int i=1;i<=k;i++){
            printf("%d:",i);
            for(int j=head[i];~j;j=e[j].nextt){
                if(e[j].v!=t&&e[j].w==1){
                    printf(" %d",e[j].v-k-n);
                }
            }
            putchar('
    ');
        }
        return 0;
    }
    View Code

    8、机器人路径规划问题

    不会题;

    9、方格取数问题

    题目链接:https://www.luogu.org/problemnew/show/P2774

    方格取数
    题目说不能取有边界

    那么我们建图的时候就按有边界的取建图;
    我们可以这样理解,我们要去掉一些格子,让整个图按要求联通,达到最大;
    把每个方格拆点,边权为方格的值,最大对应全部-最小,最小什么呢?即最小割;

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int sum=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        }
        return x?sum:-sum;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    const int M=2e4+4;
    const int inf=0x3f3f3f3f;
    struct node{
        int v,nextt,w;
    }e[200005];
    int head[M],deep[M],cur[M];
    int tot,s,t;
    int gx[4]={1,-1,0,0};
    int gy[4]={0,0,-1,1};
    int a[102][102];
    void init(){
        memset(head,-1,sizeof(head));
        tot=0;
    }
    void addedge(int u,int v,int w){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    bool bfs(){
        memset(deep,0,sizeof(deep));
        deep[s]=1;
        queue<int>que;
        que.push(s);
        while(!que.empty()){
            int u=que.front();
            que.pop();
            for(int i=head[u];~i;i=e[i].nextt){
                int v=e[i].v;
                if(e[i].w>0&&deep[v]==0){
                    deep[v]=deep[u]+1;
                    if(v==t)
                        return true;
                    que.push(v);
                }
            }
        }
        return deep[t]==0?false:true;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0,x=0;
        for(int i=cur[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==deep[u]+1){
                x=dfs(v,min(fl-ans,e[i].w));
                e[i].w-=x;
                e[i^1].w+=x;
                if(e[i].w)
                    cur[u]=i;
                ans+=x;
                if(ans==fl)
                    return ans;
            }
        }
        if(ans==0)
            deep[u]=0;
        return ans;
    }
    int dinic(int n){
        int ans=0;
        while(bfs()){
            //cout<<"!!"<<endl;
            for(int i=0;i<=n;i++)
                cur[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    int main(){
        init();
        int n=read(),m=read();
        //cout<<n<<"~~~~~"<<m<<endl;
        s=0,t=n*m+1;
        int ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                a[i][j]=read(),ans+=a[i][j];
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if((i+j)&1)
                    addedge((i-1)*m+j,t,a[i][j]);
                else
                    addedge(s,(i-1)*m+j,a[i][j]);
            }
        }
        int sign=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(!((i+j)&1)){
                    //cout<<"#####"<<sign++<<"########"<<endl;
                    for(int k=0;k<4;k++){
                        int tx=i+gx[k];
                        int ty=j+gy[k];
                        if(tx>=1&&tx<=n&&ty>=1&&ty<=m){
                            addedge((i-1)*m+j,(i-1)*m+j+(tx-i)*m+(ty-j),inf);
                            //cout<<(i-1)*m+j+(tx-i)*m+(ty-j)<<endl;
                        }
                    }
                }
                    
            }
        }
        write(ans-dinic(t));
        return 0;
    }
    View Code

    18、最长k可重区间集问题

    题:https://www.luogu.org/problem/P3358

    做法:把数轴上的每一个点向它右边的点连一条边,容量为kk,费用为00,然后把每一个区间的左端点向右端点连边,容量为11,费用为区间长度,然后求一个最大费用最大流。因为坐标太大,记得离散

    然而并不是很明白为什么这样做是对的……想了想,把网络流当成一个水流好了,水从左流到右,那么如果是在一个区间内,不可能满流(因为被区间左端点至右端点那一条边给分去了一部分流),但是被分去的那一部分流会在区间右端点被流回来,所以不想交的区间是没有影响的(因为是开区间,所以右端点和另一区间左端点重合并没有影响)。然后如果区间内还有其他区间的左端点,又会分流,一直这样下去,直到有超过kk个区间覆盖了同一点,那样流就不够了,不会再分(因为从源点也只有kk的流),那么只要求出了一个最大流,就是一个满足题目条件的方案。又因为要使长度最大,那么我们要让区间的流带上费用,求一个最大费用流即可

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int sum=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        return x?sum:-sum;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    const int M=1e4+4;
    const int N=2e3+3;
    const int inf=0x3f3f3f3f;
    typedef long long ll;
    struct node{
        ll cost;
        int v,w,nextt;
    }e[M];
    int tot,s,t;
    ll mincost;
    int head[N],cur[N],vis[N],a[N<<1],l[N],r[N];
    ll dis[N];
    void addedge(int u,int v,int w,int cost){
        e[tot].v=v;
        e[tot].w=w;
        e[tot].cost=cost;
        e[tot].nextt=head[u];
        head[u]=tot++;
        e[tot].v=u;
        e[tot].w=0;
        e[tot].cost=-cost;
        e[tot].nextt=head[v];
        head[v]=tot++;
    }
    bool bfs(){
        for(int i=0;i<=t;i++)
            dis[i]=inf;
        queue<int>que;
        que.push(s);
        dis[s]=0;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            vis[u]=0;
            for(int i=head[u];~i;i=e[i].nextt){
                int v=e[i].v;
                if(e[i].w&&dis[v]>dis[u]+e[i].cost){
                    dis[v]=dis[u]+e[i].cost;
                    if(!vis[v]){
                        vis[v]=1;
                        que.push(v);
                    }
                }
            }
        }
        return dis[t]!=inf;
    }
    int dfs(int u,int fl){
        if(u==t)
            return fl;
        int ans=0;
        vis[u]=1;
        for(int i=cur[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(!vis[v]&&e[i].w&&dis[v]==dis[u]+e[i].cost){
                cur[u]=i;
                int x=dfs(v,min(fl-ans,e[i].w));
                e[i].w-=x;
                e[i^1].w+=x;
                ans+=x;
                mincost+=1ll*x*e[i].cost;
                if(ans==fl)
                    break;
            }
        }
        vis[u]=0;
        return ans;
    }
    void MFMC(){
        while(bfs()){
            for(int i=0;i<=t;i++)
                cur[i]=head[i];
            dfs(s,inf);
        }
        
    }
    int main(){
        memset(head,-1,sizeof(head));
        int n=read(),k=read();
        for(int i=1;i<=n;i++){
            l[i]=read(),r[i]=read();
            if(l[i]>r[i])
                swap(l[i],r[i]);
            a[i]=l[i],a[i+n]=r[i];
        }
        sort(a+1,a+1+n+n);
        int m=unique(a+1,a+1+n+n)-(a+1);
        for(int i=1;i<=n;i++){
            int L=lower_bound(a+1,a+1+m,l[i])-a;
            int R=lower_bound(a+1,a+1+m,r[i])-a;
            addedge(L,R,1,l[i]-r[i]);
        }
        for(int i=2;i<=m;i++)
            addedge(i-1,i,k,0);
        s=0,t=m+1;
        addedge(s,1,k,0);
        addedge(m,t,k,0);
        MFMC();
        printf("%lld
    ",-mincost);
        return 0;
    } 
    View Code
  • 相关阅读:
    洛谷月赛 Hello World(升级版)
    codevs1001 舒适的路线
    vijos & codevs 能量项链
    vijos 运输计划
    noip2016普及组题解和心得
    UVa 10891 Game of Sum
    UVa 10635 Prince and Princess
    某模拟题题解 2016.11.17
    贪心入门题
    某模拟题题解 2016.11.16
  • 原文地址:https://www.cnblogs.com/starve/p/10891619.html
Copyright © 2020-2023  润新知