• 终点保存最大流


    这段时间朋友几篇文章介绍了改终点保存的文章. 关联文章的地址

        问题述描:需要将一批物品从节点s(源点)输送到t(成为点汇),可以从其他点直达,但是有向图的个每边上都有一个权值,表现这条边上该方向最多可以输送的物品量数
    超越这些量后以这条边就变得不可用(相当于没有这条边)
    求从s到t可以输送通过的最大物品量数。

        决解:增广路算法

        模板:

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<queue>
    #define N 55
    using namespace std;
    
    //a数组保存到个每点的小最残量,p数组保存每一条增广路的路径,cap保存各个点之间的容量
    //flow保存各个点之间的残量 
    int n,m,cap[N][N],flow[N][N],a[N],p[N];
    int maxflow(int s,int t) {
        queue<int>q;
        int f=0,u,v;//f中保存的是最大流 
        memset(flow,0,sizeof(flow));
        while(1) {
            memset(a,0,sizeof(a));
            a[s]=0x7FFFFFFF;//之所以设为最大值,一是标记问访过了,二是免避比别的残量小,从而影响找到真正的小最残量 
            q.push(s);
            while(!q.empty()) {
                u=q.front(),q.pop();
                
                for(v=1;v<=n;v++) {
                    if(!a[v]&&cap[u][v]>flow[u][v]) {//相通并且有流量,在这里a[i]=0表现这个点还没问访过,a[i]!=0的时候表现残量 
                        p[v]=u;//记录下后以结点的父节点 
                        q.push(v);//后以结点入队 
                        a[v]=a[u]<cap[u][v]-flow[u][v]?a[u]:cap[u][v]-flow[u][v];//找到到后以结点的小最残量 
                    }
                }
            }
            if(a[t]==0) break;//小最残量为0,即不再有增广路,退出 
            for(u=t;u!=s;u=p[u]) {
                flow[p[u]][u]=+a[t];//新更流量,正反两个方向 
                flow[u][p[u]]-=a[t];
                printf("%d <- ",u);
            }
            printf("%d  %d\n",s,a[t]);
            f+=a[t];
        }
        return f;
    }
    int main() {
        int T,i,j,a,b,w,f,s,t;
        scanf("%d",&T);
        while(T--) {
            scanf("%d %d %d %d",&n,&m,&s,&t);
            for(i=1;i<=n;i++)//初始化路径 
                for(j=1;j<=n;j++)
                    cap[i][j]=cap[j][i]=0;//没有容量表现通不 
            for(i=1;i<=m;i++){
                scanf("%d %d %d",&a,&b,&w);//保存刚刚输入的路的肇端和终点,便于面后新更路径
                cap[a][b]=w;
            }
            f=maxflow(s,t);
            printf("%d\n",f);
        }
        system("pause");
        return 0;
    }
    
    /*
    6 10 1 6
    1 2 16
    1 3 13
    2 3 10
    3 2 4
    3 5 14
    2 4 12
    5 4 7
    4 3 9
    5 6 4
    4 6 20
    
    
    23
    
    */

        
    这是一个基本的最大流问题,除了处置最大流问题,经过单简的形变,可以用来求二分图的最大配匹问题。如下

         述描

        每日一道理
    “多难兴才”曾一度被人定为规律。请看:屈原被放逐而作《离骚》;司马迁受宫刑而作《史记》;欧阳修两岁丧父笃学而成才;曹雪芹举家食粥而写出了不朽的《红楼梦》;越王勾践卧薪尝胆而雪洗国耻;韩信遭胯下辱而统率百万雄兵……他们都是在与逆境搏斗中成为伟人的!

    月老备准给n个女孩与n个男孩牵红线,成绩一对对美妙的姻缘。

    在现,由于一些原因,分部男孩与女孩可能结成幸福的一家,分部可能不会结成幸福的家庭。

    在现已知哪些男孩与哪些女孩如果完婚的话,可以结成幸福的家庭,月老备准成促尽可能多的幸福家庭,请你帮他找出最多可能成促的幸福家庭量数吧。

    假设男孩们分离编号为1~n,女孩们也分离编号为1~n。

     
    输入
    第一行是一个数整T,表现测试数据的组数(1<=T<=400)
    每组测试数据的第一行有两个数整n,K,其中男孩的人数与女孩的人数都是n。(n<=500,K<=10 000)
    随后的K行,每行有两个数整i,j表现第i个男孩与第j个女孩有可能结成幸福的家庭。(1<=i,j<=n)
    出输
    对每组测试数据,出输最多可能成促的幸福家庭量数
    样例输入
    1
    3 4
    1 1
    1 3
    2 2
    3 2
    样例出输
    2

    分析:我们加增一个源点和一个终点,使源点到左边集合全部点、右侧集合全部点到终点都加增一条边,且令途中多有边流量为1,则求源点到终点的最大流就是二分图的最大配匹!(对于这道题来讲,可能会时超,但是写法经过优化后之是可以过的!)

    如图所示:

    代码现实:

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #define N 1100
    using namespace std;
    
    int flow[N][N],cap[N][N],a[N],p[N];
    
    int maxflow(int s, int t){
        queue<int>q;
        int f=0,u,v;
        //memset(flow,0,sizeof(flow));
        for(u=0;u<=t;u++)
            for(v=0;v<=t;v++)
                flow[u][v]=0; 
        while(1) {
            memset(a,0,sizeof(a));
            a[s]=0x7FFFFFFF;
            q.push(s);
            while(!q.empty()) {
                u=q.front(),q.pop();
                for(v=0;v<=t;v++) {
                    if(!a[v]&&flow[u][v]<cap[u][v]){
                        p[v]=u;
                        q.push(v);
                        a[v]=a[u]<cap[u][v]-flow[u][v]?a[u]:cap[u][v]-flow[u][v];
                    }
                }
            }
            if(a[t]==0) break;
            
            for(u=t;u!=s;u=p[u]){
                flow[p[u]][u]=+a[t];//新更流量,正反两个方向 
                flow[u][p[u]]-=a[t];
            }
            f+=a[t];
        }
        return f;
    }
    
    int main() {
        int i,j,T,n,k,x,y,ans;
        scanf("%d",&T);
        while(T--) {
            scanf("%d %d",&n,&k);
            //memset(cap,0,sizeof(cap));
            for(i=0;i<2*n+2;i++)
                for(j=0;j<2*n+2;j++)
                    cap[i][j]=0; 
            for(i=1;i<=k;i++){
                scanf("%d %d",&x,&y);
                cap[x][n+y]=1;
            }
            for(i=1;i<=n;i++){//构建源点到左边集合的边 
                cap[0][i]=1;
            }
            for(i=n+1;i<=2*n;i++){//构建右侧的边到终点的边 
                cap[i][2*n+1]=1;
            }
            n=2*n+2;
            ans=maxflow(0,n-1);
            printf("%d\n",ans);
        }
        system("pause");
        return 0;
    }


     

    文章结束给大家分享下程序员的一些笑话语录: 那是习惯决定的,一直保持一个习惯是不好的!IE6的用户不习惯多标签,但是最终肯定还是得转到多标签的浏览器。历史(软件UI)的进步(改善)不是以个人意志(习惯)为转移的!

  • 相关阅读:
    maven 仓库配置 pom中repositories属性
    CentOS下SVN服务的启动与关闭
    python爬虫登录
    git pull“No remote repository specified”解决方法
    更新到mysql 5.7后解决0000-00-00日期问题
    maven仓库中有jar包pom还报错
    navicat链接mysql 8 出现 2015 authentication plugin 'caching_sha2_password' 错误
    Confluence JIRA快速入门
    SilverLight:基础控件使用(2)-ComboBox,ListBox控件
    SilverLight:基础控件使用(1)
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3052976.html
Copyright © 2020-2023  润新知