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     
没有人能阻止我前进的步伐,除了我自己!
原文地址:https://www.cnblogs.com/proverbs/p/2659164.html