• POJ 3422 K取方格数(费用流)/TYVJ 1413


    昨天刚学网络流,于是拿这道题练手。

    这道题最关键的就是建边,首先,对于这个题,限制流量是重点,我这里就提供限制流量的方法:拆点!

    (我作图水平极差,大家凑合着看吧!)

    我们把每个格子拆成两个点,这连个点之间连一条容量为1,权值为map[i][j]的边

    再连一条容量为INF,权值为0的边

    这样就限制了流量,也就是取这个格子最多只能取一次,至于以后再经过这个格子,只能通过第二条容量为INF的边,这样就取不到这个格子的数了

    为了叙述方便我们设每个格子的第一个点为1,第二个点为2

    对于一个格子的2号点,连边如上图。

    从2号点连出来的边意味着通过这个格子以后可以向下边的格子和左边的格子走

    最后对于左上角和右下角的点分别和超级源点S,和超级汇点T连一条容量为k,权为0的边(表示最多只能走k次,即k取方格数)

    ps:以上边都是有向边,抱歉,由于害怕图太乱,就没有连,大家理解思想就行了!

    这样图就建完了,然后就是模板化的跑最大费用流就好了!

    改良版:

    View Code
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <iostream>
      5 #define N 5500
      6 #define M 105000
      7 #define INF 10000000
      8 using namespace std;
      9 int to[M],next[M],len[M],w[M],from[M],head[N],pre[N],n,m,k,S,T,dis[N],q[M<<4],cnt,map[120][25],minlen[N];
     10 bool vis[N];
     11 void read()
     12 {
     13     scanf("%d%d%d",&k,&m,&n);
     14     for(int i=1;i<=n;i++)
     15         for(int j=1;j<=m;j++)
     16             scanf("%d",&map[i][j]);
     17 }
     18 int getnum(int x,int y)
     19 {
     20     return ((x-1)*m+y);
     21 }
     22 inline void add(int u,int v,int p,int wp)
     23 {
     24     from[cnt]=u; to[cnt]=v; w[cnt]=wp; len[cnt]=p; next[cnt]=head[u]; head[u]=cnt++;
     25     from[cnt]=v; to[cnt]=u; w[cnt]=-wp; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
     26 }
     27 void create()
     28 {
     29     memset(head,-1,sizeof head);
     30     cnt=0;
     31     for(int i=1,a,b,c;i<=n-1;i++)
     32         for(int j=1;j<=m-1;j++)
     33         {
     34             a=getnum(i,j); b=getnum(i,j+1); c=getnum(i+1,j);
     35             add(a<<1,a<<1|1,1,map[i][j]);  add(a<<1,a<<1|1,INF,0);
     36             add(a<<1|1,b<<1,INF,0); add(a<<1|1,c<<1,INF,0);
     37         }
     38     for(int j=1,a,b;j<=m-1;j++)
     39     {
     40         a=getnum(n,j); b=getnum(n,j+1);
     41         add(a<<1,a<<1|1,1,map[n][j]);  add(a<<1,a<<1|1,INF,0);
     42         add(a<<1|1,b<<1,INF,0);
     43     }
     44     for(int i=1,a,c;i<=n-1;i++)
     45     {
     46         a=getnum(i,m); c=getnum(i+1,m);
     47         add(a<<1,a<<1|1,1,map[i][m]); add(a<<1,a<<1|1,INF,0);
     48         add(a<<1|1,c<<1,INF,0);
     49     }
     50     int a=getnum(n,m);
     51     add(a<<1,a<<1|1,1,map[n][m]);  add(a<<1,a<<1|1,INF,0);
     52     S=0; T=n*m*2+7;
     53     add(S,getnum(1,1)<<1,k,0);  
     54     add(getnum(n,m)<<1|1,T,k,0);
     55 }
     56 bool spfa()
     57 {
     58     minlen[S]=INF;
     59     for(int i=0;i<=T;i++) dis[i]=-INF;
     60     memset(pre,-1,sizeof pre);
     61     int h=1,t=2,sta;
     62     q[1]=S; vis[S]=true; dis[S]=0;
     63     while(h<t)
     64     {
     65         sta=q[h++];
     66         vis[sta]=false;
     67         for(int i=head[sta];~i;i=next[i])
     68             if(len[i]>0&&dis[to[i]]<dis[sta]+w[i])
     69             {
     70                 dis[to[i]]=dis[sta]+w[i];
     71                 minlen[to[i]]=min(minlen[sta],len[i]);
     72                 pre[to[i]]=i;
     73                 if(!vis[to[i]])
     74                 {
     75                     vis[to[i]]=true;
     76                     q[t++]=to[i];
     77                 }
     78             }
     79     }
     80     if(pre[T]==-1) return false;
     81     else return true;
     82 }
     83 void dec()
     84 {
     85     int tmp=pre[T];
     86     while(tmp!=-1)
     87     {
     88         len[tmp]-=minlen[T];
     89         len[tmp^1]+=minlen[T];
     90         tmp=pre[from[tmp]];
     91     }
     92 }
     93 int max_fee()
     94 {
     95     int ans=0;
     96     while(spfa())
     97     {
     98         ans+=dis[T];
     99         dec();
    100     }
    101     return ans;
    102 }
    103 int main()
    104 {
    105     read();
    106     create();
    107     printf("%d\n",max_fee());
    108     system("pause");
    109     return 0;
    110 }
    111     

    乱连边版:

    View Code
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <iostream>
      5 #define N 5500
      6 #define M 105000
      7 #define INF 10000000
      8 using namespace std;
      9 int to[M],next[M],len[M],w[M],from[M],head[N],pre[N],n,m,k,S,T,dis[N],q[M<<4],cnt,map[120][25],minlen[N];
     10 bool vis[N];
     11 void read()
     12 {
     13     scanf("%d%d%d",&k,&m,&n);
     14     for(int i=1;i<=n;i++)
     15         for(int j=1;j<=m;j++)
     16             scanf("%d",&map[i][j]);
     17 }
     18 int getnum(int x,int y)
     19 {
     20     return ((x-1)*m+y);
     21 }
     22 inline void add(int u,int v,int p,int wp)
     23 {
     24     from[cnt]=u; to[cnt]=v; w[cnt]=wp; len[cnt]=p; next[cnt]=head[u]; head[u]=cnt++;
     25     from[cnt]=v; to[cnt]=u; w[cnt]=-wp; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
     26 }
     27 void create()
     28 {
     29     memset(head,-1,sizeof head);
     30     cnt=0;
     31     for(int i=1,a,b,c;i<=n-1;i++)
     32         for(int j=1;j<=m-1;j++)
     33         {
     34             a=getnum(i,j); b=getnum(i,j+1); c=getnum(i+1,j);
     35             add(a<<1,a<<1|1,1,map[i][j]);
     36             add(a<<1,b<<1,INF,0);  add(a<<1,b<<1|1,INF,0);  add(a<<1|1,b<<1,INF,0);  add(a<<1|1,b<<1|1,INF,0);
     37             add(a<<1,c<<1,INF,0);  add(a<<1,c<<1|1,INF,0);  add(a<<1|1,c<<1,INF,0);  add(a<<1|1,c<<1|1,INF,0);
     38         }
     39     for(int j=1,a,b;j<=m-1;j++)
     40     {
     41         a=getnum(n,j); b=getnum(n,j+1);
     42         add(a<<1,a<<1|1,1,map[n][j]);
     43         add(a<<1,b<<1,INF,0);  add(a<<1,b<<1|1,INF,0);  add(a<<1|1,b<<1,INF,0);  add(a<<1|1,b<<1|1,INF,0);
     44     }
     45     for(int i=1,a,c;i<=n-1;i++)
     46     {
     47         a=getnum(i,m); c=getnum(i+1,m);
     48         add(a<<1,a<<1|1,1,map[i][m]);
     49         add(a<<1,c<<1,INF,0);  add(a<<1,c<<1|1,INF,0);  add(a<<1|1,c<<1,INF,0);  add(a<<1|1,c<<1|1,INF,0);
     50     }
     51     int a=getnum(n,m);
     52     add(a<<1,a<<1|1,1,map[n][m]);
     53     S=0; T=n*m*2+7;
     54     add(S,getnum(1,1)<<1,k,0);  
     55     add(getnum(n,m)<<1|1,T,k,0);
     56 }
     57 bool spfa()
     58 {
     59     minlen[S]=INF;
     60     for(int i=0;i<=T;i++) dis[i]=-INF;
     61     memset(pre,-1,sizeof pre);
     62     int h=1,t=2,sta;
     63     q[1]=S; vis[S]=true; dis[S]=0;
     64     while(h<t)
     65     {
     66         sta=q[h++];
     67         vis[sta]=false;
     68         for(int i=head[sta];~i;i=next[i])
     69             if(len[i]>0&&dis[to[i]]<dis[sta]+w[i])
     70             {
     71                 dis[to[i]]=dis[sta]+w[i];
     72                 minlen[to[i]]=min(minlen[sta],len[i]);
     73                 pre[to[i]]=i;
     74                 if(!vis[to[i]])
     75                 {
     76                     vis[to[i]]=true;
     77                     q[t++]=to[i];
     78                 }
     79             }
     80     }
     81     if(pre[T]==-1) return false;
     82     else return true;
     83 }
     84 void dec()
     85 {
     86     int tmp=pre[T];
     87     while(tmp!=-1)
     88     {
     89         len[tmp]-=minlen[T];
     90         len[tmp^1]+=minlen[T];
     91         tmp=pre[from[tmp]];
     92     }
     93 }
     94 int max_fee()
     95 {
     96     int ans=0;
     97     while(spfa())
     98     {
     99         ans+=dis[T];
    100         dec();
    101     }
    102     return ans;
    103 }
    104 int main()
    105 {
    106     read();
    107     create();
    108     printf("%d\n",max_fee());
    109     system("pause");
    110     return 0;
    111 }
    112     
    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    C# ref与out区别
    天气预报
    全面理解javascript的caller,callee,call,apply概念(修改版)
    SQL注入案例曝光,请大家提高警惕
    sql字段保存值[1,2,3,4,5]复杂取法,收藏sql函数
    MySQL故障诊断常用方法手册(含脚本、案例)
    2021 年 8 月国产数据库排行榜:秋日胜春朝
    【墨天轮专访第二期】巨杉数据库萧少聪:重视企业长期需求,打造中国的世界级产品
    【我和达梦的故事】 有奖征文活动开始啦,万元奖品池+现金奖励等你拿!
    2021年8月国产数据库排行榜:TiDB稳榜首,达梦返前三,Kingbase进十强,各厂商加速布局云生态
  • 原文地址:https://www.cnblogs.com/proverbs/p/2659164.html
Copyright © 2020-2023  润新知