【PowerOJ1751&网络流24题】数字梯形问题(费用流)

题意:

 思路:

【问题分析】

求图的最大权不相交路径及其变种,用费用最大流解决。

【建模方法】

规则(1)

把梯形中每个位置抽象为两个点<i.a>,<i.b>,建立附加源S汇T。

1、对于每个点i从<i.a>到<i.b>连接一条容量为1,费用为点i权值的有向边。

2、从S向梯形顶层每个<i.a>连一条容量为1,费用为0的有向边。

3、从梯形底层每个<i.b>向T连一条容量为1,费用为0的有向边。

4、对于每个点i和下面的两个点j,分别连一条从<i.b>到<j.a>容量为1,费用为0的有向边。

求最大费用最大流,费用流值就是结果。

规则(2)

把梯形中每个位置看做一个点i,建立附加源S汇T。

1、从S向梯形顶层每个i连一条容量为1,费用为0的有向边。

2、从梯形底层每个i向T连一条容量为无穷大,费用为0的有向边。

3、对于每个点i和下面的两个点j,分别连一条从i到j容量为1,费用为点i权值的有向边。

求最大费用最大流,费用流值就是结果。

规则(3)

把梯形中每个位置看做一个点i,建立附加源S汇T。

1、从S向梯形顶层每个i连一条容量为1,费用为0的有向边。

2、从梯形底层每个i向T连一条容量为无穷大,费用为0的有向边。

3、对于每个点i和下面的两个点j,分别连一条从i到j容量为无穷大,费用为点i权值的有向边。

求最大费用最大流,费用流值就是结果。

【建模分析】

对于规则1,要求路径完全不相交,也就是每个点最多只能被访问了一次,所以要把点拆分,之间连接容量为1的边。因为任意一条ST之间的路径都是一个解,在拆分的点内部的边费用设为点的权值,求

最大费用最大流就是费用最大的m条路经。

对于规则2,要求路径可以相交,但不能有重叠,此时可以不必拆点了。为了保证路径没有重叠,需要在相邻的两个点上限制流量为1,由于顶层的每个点只能用1次,S向顶层点流量限制也为1。费用只需

设在相邻点的边上,求最大费用最大流即可。

对于规则3,要求路径除了顶层每个点以外可以任意相交重叠。在规则2的基础上,取消除S到顶层顶点之间的边以外所有边的流量限制即可。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 typedef unsigned int uint;
  5 typedef unsigned long long ull;
  6 typedef long double ld;
  7 typedef pair<int,int> PII;
  8 typedef pair<ll,ll> Pll;
  9 typedef vector<int> VI;
 10 typedef vector<PII> VII;
 11 typedef pair<ll,ll>P;
 12 #define N  100010
 13 #define M  1000000
 14 #define INF 1e9
 15 #define fi first
 16 #define se second
 17 #define MP make_pair
 18 #define pb push_back
 19 #define pi acos(-1)
 20 #define mem(a,b) memset(a,b,sizeof(a))
 21 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
 22 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
 23 #define lowbit(x) x&(-x)
 24 #define Rand (rand()*(1<<16)+rand())
 25 #define id(x) ((x)<=B?(x):m-n/(x)+1)
 26 #define ls p<<1
 27 #define rs p<<1|1
 28 
 29 const ll MOD=1e9+7,inv2=(MOD+1)/2;
 30       double eps=1e-6;
 31       int dx[4]={-1,1,0,0};
 32       int dy[4]={0,0,-1,1};
 33 
 34 int head[N],vet[N],len1[N],len2[N],nxt[N],dis[N],q[N],inq[N],a[50][50],
 35     num[50][50][2],pre[N][2],s,S,T,tot,ans1,ans2,n,m;
 36 
 37 
 38 
 39 int read()
 40 {
 41    int v=0,f=1;
 42    char c=getchar();
 43    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
 44    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 45    return v*f;
 46 }
 47 
 48 void add(int a,int b,int c,int d)
 49 {
 50     nxt[++tot]=head[a];
 51     vet[tot]=b;
 52     len1[tot]=c;
 53     len2[tot]=d;
 54     head[a]=tot;
 55 
 56     nxt[++tot]=head[b];
 57     vet[tot]=a;
 58     len1[tot]=0;
 59     len2[tot]=-d;
 60     head[b]=tot;
 61 }
 62 
 63 int spfa()
 64 {
 65     rep(i,1,s)
 66     {
 67         dis[i]=-INF;
 68         inq[i]=0;
 69     }
 70     int t=0,w=1;
 71     q[1]=S; dis[S]=0; inq[S]=1;
 72     while(t<w)
 73     {
 74         t++; int u=q[t%(s+5)]; inq[u]=0;
 75         int e=head[u];
 76         while(e)
 77         {
 78             int v=vet[e];
 79             if(len1[e]&&dis[u]+len2[e]>dis[v])
 80             {
 81                 dis[v]=dis[u]+len2[e];
 82                 pre[v][0]=u;
 83                 pre[v][1]=e;
 84                 if(!inq[v])
 85                 {
 86                     w++; q[w%(s+5)]=v; inq[v]=1;
 87                 }
 88             }
 89             e=nxt[e];
 90         }
 91     }
 92     if(dis[T]==-INF) return 0;
 93     return 1;
 94 }
 95 
 96 void mcf()
 97 {
 98     int k=T;
 99     int t=INF;
100     while(k!=S)
101     {
102         int e=pre[k][1];
103         t=min(t,len1[e]);
104         k=pre[k][0];
105     }
106     ans1+=t;
107     k=T;
108     while(k!=S)
109     {
110         int e=pre[k][1];
111         len1[e]-=t;
112         len1[e^1]+=t;
113         ans2+=t*len2[e];
114         k=pre[k][0];
115     }
116 }
117 
118 void solve1()
119 {
120     tot=1;
121     rep(i,1,s) head[i]=0;
122     rep(i,1,m) add(S,num[1][i][0],1,0);
123     rep(i,1,n-1)
124      rep(j,1,m+i-1)
125      {
126          add(num[i][j][1],num[i+1][j][0],1,0);
127          add(num[i][j][1],num[i+1][j+1][0],1,0);
128      }
129     rep(i,1,n)
130      rep(j,1,m+i-1) add(num[i][j][0],num[i][j][1],1,a[i][j]);
131     rep(i,1,n+m-1) add(num[n][i][1],T,1,0);
132     ans1=ans2=0;
133     while(spfa()) mcf();
134     printf("%d\n",ans2);
135 }
136 
137 void solve2()
138 {
139     tot=1;
140     rep(i,1,s) head[i]=0;
141     rep(i,1,m) add(S,num[1][i][0],1,0);
142     rep(i,1,n-1)
143      rep(j,1,m+i-1)
144      {
145          add(num[i][j][0],num[i+1][j][0],1,a[i][j]);
146          add(num[i][j][0],num[i+1][j+1][0],1,a[i][j]);
147      }
148     rep(i,1,n+m-1) add(num[n][i][0],T,INF,a[n][i]);
149     ans1=ans2=0;
150     while(spfa()) mcf();
151     printf("%d\n",ans2);
152 }
153 
154 void solve3()
155 {
156     tot=1;
157     rep(i,1,s) head[i]=0;
158     rep(i,1,m) add(S,num[1][i][0],1,0);
159     rep(i,1,n-1)
160      rep(j,1,m+i-1)
161      {
162          add(num[i][j][0],num[i+1][j][0],INF,a[i][j]);
163          add(num[i][j][0],num[i+1][j+1][0],INF,a[i][j]);
164      }
165     rep(i,1,n+m-1) add(num[n][i][0],T,INF,a[n][i]);
166     ans1=ans2=0;
167     while(spfa()) mcf();
168     printf("%d\n",ans2);
169 }
170 
171 int main()
172 {
173     //freopen("1.in","r",stdin);
174     m=read(),n=read();
175     s=0;
176     rep(i,1,n)
177      rep(j,1,m+i-1)
178      {
179          a[i][j]=read();
180          num[i][j][0]=++s;
181          num[i][j][1]=++s;
182      }
183     S=++s,T=++s;
184     solve1();
185     solve2();
186     solve3();
187     return 0;
188 }

猜你喜欢

转载自www.cnblogs.com/myx12345/p/11761880.html