您的位置:首页 > 其它

wiki 1913 数字梯形问题

2014-07-24 13:11 344 查看
这是一道很经典的费用流题目,可以通过最大费用最大流实现

通过分析题目,我们很容易想到建模方法:

1、对于规则一,题目规定每一个节点只能访问一次,也就是说,实际上这个时候每一个点都有容量限制,所以我们必须把点i拆分成两个点Xi,Yi。此时每一条边的容量都是1,费用为改点的权值,此时只允许使用该节点一次,并且代价为权值。数字梯形是逐层向下的,并且每一个点可以向下面两个方向进行扩展,于是我们在这些点之间建立容量为1,费用为0的边。对于最顶层与最底层,我们分让两层分别与源点和汇点相连,容量同样是1,费用为0。(注意所有的边都是有向边,并且结点i与j相连是指Yi与Xj相连)

2、对于规则二,由于可以共点,所以就不用拆点了,源点与上层继续保持容量为1,其他的关联除了不用拆点外,其他都差不多,注意一下底层与汇点的容量限制改为无穷大即可。

3、对于规则三,由于边和节点都可以共用,此时没有必要把原网络销毁,直接在上一个规则的前提下修改每一条边的容量即可(注意源点与顶层节点之间的容量是不能变的,否则就无法满足是m条路径取得的最大值,其他边的容量改成无穷大即可)

上面是我摘录的别人的题解,我的代码跟这个题解思路完全一致,我的AC代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<iomanip>
#include<queue>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<algorithm>

using namespace std;
const int INF = 1<<30;
const int maxN = 2000;
int m,n,s,t,result;
int mymap[50][50];
struct Edge{
int from, to, cap, flow, cost;
};
vector<Edge> es;
vector<int> g[maxN];
int pos[50][50][2];
int dir[2][2] = {1,0,1,1};
void addedge (int from, int to, int cap, int cost){
es.push_back(Edge{from, to, cap, 0, cost});
es.push_back(Edge{to, from, 0, 0, -cost});
int u = es.size();
g[from].push_back(u-2);
g[to].push_back(u-1);
}
void init(){
cin >> m >> n;
memset(mymap, -1, sizeof(mymap));
for(int i = 0; i < n; i++){
for(int j = 0; j < m+i; j++){
cin >> mymap[i][j];
}
}
}
void make1(){
memset(pos, -1, sizeof(pos));
int sz = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m+i; j++){
pos[i][j][0] = sz++;
pos[i][j][1] = sz++;
}
}
s = sz++;
t = sz++;
for(int i = 0; i < m; i++) addedge(s, pos[0][i][0], 1, 0);
for(int i = 0; i < n; i++){
for(int j = 0; j < m+i; j++){
addedge(pos[i][j][0], pos[i][j][1], 1, -mymap[i][j]);
for(int u = 0; u < 2; u++){
int x = i + dir[u][0];
int y = j + dir[u][1];
if(x < n){
addedge(pos[i][j][1], pos[x][y][0], 1, 0);
}
}
}
}
for(int i = 0; i < m+n-1; i++){
addedge(pos[n-1][i][1], t, 1, 0);
}
}
void solve (){
int a[maxN],d[maxN],p[maxN],inq[maxN];
memset(a, 0, sizeof(a));
a[s] = INF;
while(true){
for(int i = 0; i < maxN; i++) d[i] = INF;
d[s] = 0;
memset(inq, 0, sizeof(inq));
queue<int> q;
q.push(s);
inq[s] = 1;
while(!q.empty()){
int u = q.front();
q.pop();
inq[u] = 0;
for(int i = 0; i < g[u].size(); i++){
Edge& e = es[g[u][i]];
if(e.cap>e.flow && d[e.to] > d[e.from]+e.cost){
a[e.to] = (a[e.from] > e.cap-e.flow ? e.cap-e.flow : a[e.from]);
d[e.to] = d[e.from] + e.cost;
p[e.to] = g[u][i];
if(!inq[e.to]) {q.push(e.to); inq[e.to] = 1;}
}
}
}
if(d[t]==INF) break;
result += -(d[t]*a[t]);
int u = t;
while(u!=s){
es[p[u]].flow += a[t];
es[p[u]^1].flow -= a[t];
u = es[p[u]].from;
}
}
}
void make2(){
memset(pos, -1, sizeof(pos));
int sz = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m+i; j++){
pos[i][j][0] = sz++;
}
}
s = sz++;
t = sz++;
for(int i = 0; i < m; i++) addedge(s, pos[0][i][0], 1, -mymap[0][i]);
for(int i = 0; i < n; i++){
for(int j = 0; j < m+i; j++){
for(int u = 0; u < 2; u++){
int x = i + dir[u][0];
int y = j + dir[u][1];
if(x < n){
addedge(pos[i][j][0], pos[x][y][0], 1, -mymap[x][y]);
}
}
}
}
for(int i = 0; i < m+n-1; i++){
addedge(pos[n-1][i][0], t, INF, 0);
}
}
void make3 (){
memset(pos, -1, sizeof(pos));
int sz = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m+i; j++){
pos[i][j][0] = sz++;
}
}
s = sz++;
t = sz++;
for(int i = 0; i < m; i++) addedge(s, pos[0][i][0], 1, -mymap[0][i]);
for(int i = 0; i < n; i++){
for(int j = 0; j < m+i; j++){
for(int u = 0; u < 2; u++){
int x = i + dir[u][0];
int y = j + dir[u][1];
if(x < n){
addedge(pos[i][j][0], pos[x][y][0], INF, -mymap[x][y]);
}
}
}
}
for(int i = 0; i < m+n-1; i++){
addedge(pos[n-1][i][0], t, INF, 0);
}
}
int main(int argc, const char * argv[])
{
init();
es.clear();
for(int i = 0; i < maxN; i++) g[i].clear();
make1();
solve();
cout << result << endl;

es.clear();
for(int i = 0; i < maxN; i++) g[i].clear();
result = 0;
make2();
solve();
cout << result << endl;

es.clear();
for(int i = 0; i < maxN; i++) g[i].clear();
result = 0;
make3();
solve();
cout << result << endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息