最大最小费用流

题目在这里https://hihocoder.com/problemset/problem/1591?sid=1197871

理解题目,用费用流以后,就抄个模板,建好图,跑就行。

源代码在这里http://blog.csdn.net/jzq233jzq/article/details/73123089

下面贴上代码,需要的时候,拷贝一下就行。

  1 #include<bits/stdc++.h>
  2 #define pb push_back
  3 typedef long long ll;
  4 using namespace std;
  5 typedef pair<int, int> pii;
  6 const int maxn = 1e3 + 10;
  7 bool vis[200001];int dist[200001];
  8 //解释一下各数组的含义:vis两个用处:spfa里的访问标记,増广时候的访问标记,dist是每个点的距离标号
  9 int n,m,s,t,ans=0;
 10 //s是起点,t是终点,ans是费用答案
 11 int nedge=-1,p[200001],c[200001],cc[200001],nex[200001],head[200001];
 12 //这里是边表,解释一下各数组的含义:p[i]表示以某一点出发的编号为i的边对应点,c表示编号为i的边的流量,cc表示编号为i的边的费用,nex和head不说了吧。。。
 13 inline void addedge(int x,int y,int z,int zz){
 14     p[++nedge]=y;c[nedge]=z;cc[nedge]=zz;nex[nedge]=head[x];head[x]=nedge;
 15 }
 16 //建边(数组模拟边表倒挂)
 17 inline bool spfa(int s,int t){
 18     memset(vis,0,sizeof vis);
 19     for(int i=0;i<=n;i++)dist[i]=1e9;dist[t]=0;vis[t]=1;
 20 //首先SPFA我们维护距离标号的时候要倒着跑,这样可以维护出到终点的最短路径
 21     deque<int>q;q.push_back(t);
 22 //使用了SPFA的SLF优化(SLF可以自行百度或Google)
 23     while(!q.empty()){
 24         int now=q.front();q.pop_front();
 25         //cout << now << " ddd " << endl;
 26         for(int k=head[now];k>-1;k=nex[k])if(c[k^1]&&dist[p[k]]>dist[now]-cc[k]){
 27 //首先c[k^1]是为什么呢,因为我们要保证正流,但是SPFA是倒着跑的,所以说我们要求c[k]的对应反向边是正的,这样保证走的方向是正确的
 28             dist[p[k]]=dist[now]-cc[k];
 29 //因为已经是倒着的了,我们也可以很清楚明白地知道建边的时候反向边的边权是负的,所以减一下就对了(负负得正)
 30             if(!vis[p[k]]){
 31                 vis[p[k]]=1;
 32                 if(!q.empty()&&dist[p[k]]<dist[q.front()])q.push_front(p[k]);else q.push_back(p[k]);
 33 //SLF优化
 34             }
 35         }
 36         vis[now]=0;
 37     }
 38     return dist[s]<1e9;
 39 //判断起点终点是否连通
 40 }
 41 inline int dfs(int x,int low){
 42 //这里就是进行増广了
 43     if(x==t){vis[t]=1;return low;}
 44     int used=0,a;vis[x]=1;
 45 //这边是不是和dinic很像啊
 46     for(int k=head[x];k>-1;k=nex[k])if(!vis[p[k]]&&c[k]&&dist[x]-cc[k]==dist[p[k]]){
 47 //这个条件就表示这条边可以进行増广
 48         a=dfs(p[k],min(c[k],low-used));
 49         if(a)ans+=a*cc[k],c[k]-=a,c[k^1]+=a,used+=a;
 50 //累加答案,加流等操作都在这了
 51         if(used==low)break;
 52     }
 53     return used;
 54 }
 55 inline int costflow(){
 56     int flow=0;
 57     while(spfa(s,t)){
 58 //判断起点终点是否连通,不连通说明满流,做完了退出
 59         //cout <<"asd" << endl;
 60         vis[t]=1;
 61         while(vis[t]){
 62             memset(vis,0,sizeof vis);
 63             flow+=dfs(s,1e9);
 64 //一直増广直到走不到为止(这样也可以省时间哦)
 65         }
 66     }
 67     return flow;//这里返回的是最大流,费用的答案在ans里
 68 }
 69 int tn, tmc;
 70 int tc[110];
 71 int te[110][110];
 72 int ta[110][110];
 73 int solve()
 74 {
 75     cin >> tn;
 76     for (int i = 1; i <= tn; i++) cin >>tc[i];
 77     cin >> tmc;
 78     int x, y;
 79     for (int i = 0; i < tmc; i++) {
 80         cin >> x >> y;
 81         te[x][y] = 1; te[y][x] = -1;
 82     }
 83     for (int i = 1; i <= tn; i++) {
 84         for (int j = 1; j <= tn; j++)
 85             cin >> ta[i][j];
 86     }
 87     memset(nex,-1,sizeof nex);memset(head,-1,sizeof head);
 88     //scanf("%d%d%d%d",&n,&m,&s,&t);
 89     n = tn * (tn - 1) / 2 + tn + 2 + 1;
 90     s = n - 1; t = s - 1;
 91     for (int i = 1; i <= tn; i++) {
 92         addedge(i, t, tc[i], 0);addedge(t, i, 0, 0);
 93     }
 94     int cur = tn;
 95     for (int i = 1; i <= tn; i++) {
 96         for(int j = i + 1; j <= tn; j++) {
 97             cur++;
 98             addedge(s, cur, 1, 0); addedge(cur, s, 0, 0);
 99             if(te[i][j] > 0) {
100                 addedge(cur, i, 1, -ta[i][j]);addedge(i, cur, 0, ta[i][j]);
101                 //cout << cur << " " << i <<" " << j <<" " <<ta[i][j] << endl;
102             } else if(te[i][j] == 0) {
103                 addedge(cur, i, 1, -ta[i][j]);addedge(i, cur, 0, ta[i][j]);
104                 addedge(cur, j, 1, -ta[j][i]);addedge(j, cur, 0, ta[j][i]);
105             } else {
106                 addedge(cur, j, 1, -ta[j][i]);addedge(j, cur, 0, ta[j][i]);
107             }
108         }
109     }
110     /*
111     for(int i=1;i<=m;i++){
112         int x,y,z,zz;scanf("%d%d%d%d",&x,&y,&z,&zz);
113         addedge(x,y,z,zz);addedge(y,x,0,-zz);
114     } */
115     costflow();
116     //printf("%d ",costflow());
117     printf("%d",-ans);
118     return 0;
119 }
120 
121 int main() {
122     freopen("test.in", "r", stdin);
123     //freopen("test.out", "w", stdout);
124     solve();
125     return 0;
126 }
View Code
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int N = 103;
  5 int match[N][N], matchIdx;
  6 
  7 const int MAXN = 10011;
  8 const int MAXM = 100011;
  9 const int INF = (1 << 30);
 10 
 11 struct Edge {
 12     int next, from, to, cap, cost;
 13 };
 14 
 15 struct MCMF {
 16     Edge edge[MAXM];
 17     int head[MAXN], countedge;
 18 
 19     void Init(int N) {
 20         this->N = N;
 21         memset(head, -1, sizeof(head));
 22         countedge = 0;
 23     }
 24 
 25     int N;
 26     int inq[MAXN], dis[MAXN], pre[MAXN], ad[MAXN];
 27 
 28     void AddEdge(const int& start, const int& end, const int& cap,
 29                  const int& cost) {
 30         edge[countedge].to = end;
 31         edge[countedge].from = start;
 32         edge[countedge].next = head[start];
 33         edge[countedge].cap = cap;
 34         edge[countedge].cost = cost;
 35         head[start] = countedge++;
 36         edge[countedge].to = start;
 37         edge[countedge].from = end;
 38         edge[countedge].next = head[end];
 39         edge[countedge].cap = 0;
 40         edge[countedge].cost = -cost;
 41         head[end] = countedge++;
 42     }
 43 
 44     bool BF(int s, int t, int& cost) {
 45         int i;
 46         for (i = 0; i < N; i++) dis[i] = INF;
 47         memset(inq, 0, sizeof(inq));
 48         dis[s] = 0;
 49         inq[s] = 1;
 50         pre[s] = -1;
 51         ad[s] = INF;
 52 
 53         queue<int> que;
 54         que.push(s);
 55         int u, v, temp;
 56         while (!que.empty()) {
 57             u = que.front();
 58             que.pop();
 59             inq[u] = 0;
 60             for (temp = head[u]; temp != -1; temp = edge[temp].next) {
 61                 v = edge[temp].to;
 62                 if (edge[temp].cap && dis[v] > dis[u] + edge[temp].cost) {
 63                     dis[v] = dis[u] + edge[temp].cost;
 64                     pre[v] = temp;
 65                     ad[v] = min(ad[u], edge[temp].cap);
 66                     if (!inq[v]) {
 67                     inq[v] = 1;
 68                     que.push(v);
 69                     }
 70                 }
 71             }
 72         }
 73         if (dis[t] == INF) return false;
 74         cost += dis[t] * ad[t];
 75         u = t;
 76         while (u != s) {
 77             edge[pre[u]].cap -= ad[t];
 78             edge[pre[u] ^ 1].cap += ad[t];
 79             u = edge[pre[u]].from;
 80         }
 81         return true;
 82     }
 83 
 84     int MinC(int s, int t) {
 85     int cost = 0;
 86     while (BF(s, t, cost))
 87         ;
 88     return cost;
 89     }
 90 }f;
 91 
 92 int score[N];
 93 bool ban[N][N];
 94 int u[10011], v[10011];
 95 int add[N][N];
 96 
 97 int main() {
 98     int n;
 99     scanf("%d", &n);
100 
101     f.Init(n + n * (n - 1) / 2 + 2);
102     int S = n + n * (n - 1) / 2, T = S + 1;
103     for (int i = 0; i < n; i++) {
104         scanf("%d", &score[i]);
105         f.AddEdge(S, i, score[i], 0);
106     }
107 
108     matchIdx = n;
109     for (int i = 0; i < n; i++) {
110         for (int j = i + 1; j < n; j++) {
111             match[i][j] = matchIdx++;
112             f.AddEdge(match[i][j], T, 1, 0);
113         }
114     }
115 
116     int see;
117     scanf("%d", &see);
118     for(int i = 0; i < see; i++) {
119         scanf("%d%d", &u[i], &v[i]);
120         u[i]--;
121         v[i]--;
122         ban[v[i]][u[i]] = true;
123     }
124 
125     for(int i = 0; i < n; i++) {
126         for(int j = 0; j < n; j++) {
127             scanf("%d", &add[i][j]);
128             if(i == j) {
129                 continue;
130             }
131             if(!ban[i][j]) {
132                 f.AddEdge(i, match[min(i, j)][max(i, j)], 1, -add[i][j]);
133             }
134         }
135     }
136 
137     cout << -f.MinC(S, T) << endl;
138 
139     return 0;
140 }
View Code

hihocode offer收割赛33 第三题, 第二名,比较好的模板

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int N = 200 + 5;
  6 const int NN = N * N * 2 + 5;
  7 const int M = NN * 4 + 5;
  8 
  9 struct Edge {
 10   int u, v, c, cost, nxt;
 11   Edge() {}
 12   Edge(int _u, int _v, int _c, int _cost, int _nxt)
 13     : u(_u), v(_v), c(_c), cost(_cost), nxt(_nxt) {}
 14 } es[M];
 15 
 16 int head[NN], from[NN], dp[NN], tot;
 17 
 18 int n;
 19 int x[N][N];
 20 
 21 void addEdge(int u, int v, int c, int cost) {
 22   es[tot] = Edge(u, v, c, cost, head[u]);
 23   head[u] = tot++;
 24 }
 25 
 26 void addDoubleEdge(int u, int v, int c, int cost) {
 27   addEdge(u, v, c, cost);
 28   addEdge(v, u, 0, -cost);
 29 }
 30 
 31 int spfa(int s, int t) {
 32   deque <int> de;
 33   memset(dp, -1, sizeof dp);
 34   dp[s] = 0;
 35   de.push_back(s);
 36   while (!de.empty()) {
 37     int u = de.front();
 38     de.pop_front();
 39     for (int i = head[u]; i != -1; i = es[i].nxt) {
 40       if (es[i].c == 0)
 41         continue;
 42       int v = es[i].v;
 43       if (dp[v] < dp[u] + es[i].cost) {
 44         dp[v] = dp[u] + es[i].cost;
 45         from[v] = i;
 46         de.push_back(v);
 47       }
 48     }
 49   }
 50   if (dp[t] == -1)
 51     return dp[t];
 52   int temp = t;
 53   while (temp != s) {
 54     int id = from[temp];
 55     --es[id].c;
 56     ++es[id ^ 1].c;
 57     temp = es[id].u;
 58   }
 59   return dp[t];
 60 }
 61 
 62 int mcmf(int s, int t) {
 63   int ret = 0;
 64   while (true) {
 65     int add = spfa(s, t);
 66     if (add == -1)
 67       break;
 68     ret += add;
 69   }
 70   return ret;
 71 }
 72 
 73 int main()
 74 {
 75   ios::sync_with_stdio(false);
 76   cin.tie(nullptr); cout.tie(nullptr);
 77 
 78   cin >> n;
 79   for (int i = 0; i < n; ++i)
 80     for (int j = 0; j < n; ++j)
 81       cin >> x[i][j];
 82   
 83   int all = n * n;
 84   tot = 0;
 85   memset(head, -1, sizeof head);
 86   for (int i = 0; i < n; ++i) {
 87     for (int j = 0; j < n; ++j) {
 88       int c = 1;
 89       if (i == 0 && j == 0)
 90         c = 2;
 91       if (i == n - 1 && j == n - 1)
 92         c = 2;
 93       addDoubleEdge(i * n + j, i * n + j + all, c, x[i][j]);
 94       if (i + 1 < n)
 95         addDoubleEdge(i * n + j + all, (i + 1) * n + j, 1, 0);
 96       if (j + 1 < n)
 97         addDoubleEdge(i * n + j + all, i * n + j + 1, 1, 0);
 98     }
 99   }
100   int s = all + all, t = s + 1;
101   addDoubleEdge(s, 0, 2, 0);
102   addDoubleEdge(all + all - 1, t, 2, 0);
103   cout << mcmf(s, t) << '
';
104   return 0;
105 }
View Code
原文地址:https://www.cnblogs.com/y119777/p/7597066.html