FZU2143Board Game(最小费用流)

题目大意是说有一个B矩阵,现在A是一个空矩阵(每个元素都为0),每次操作可以将A矩阵相邻的两个元素同时+1,但是有个要求就是A矩阵的每个元素都不可以超过K,求

这个的最小值

解题思路是这样的,新建起点与奇点(i != j)连K条边,第i条边的权值为(i - B)^2 - (i - 1 - B)^2 = 2 * i - 1 - 2 * B(这样可以保证如果此边的流量为a, 花费始终是(a-b)^2);另外新建终点与偶点相连,代价与上诉一致;

然后跑一遍最小费用流,知道cost>=0时为止。祥见代码:

  1 #include <map>
  2 #include <set>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <vector>
  8 #include <cstdio>
  9 #include <cctype>
 10 #include <cstring>
 11 #include <cstdlib>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15 #define INF 0x3f3f3f3f
 16 #define inf (-((LL)1<<40))
 17 #define lson k<<1, L, mid
 18 #define rson k<<1|1, mid+1, R
 19 #define mem0(a) memset(a,0,sizeof(a))
 20 #define mem1(a) memset(a,-1,sizeof(a))
 21 #define mem(a, b) memset(a, b, sizeof(a))
 22 #define FIN freopen("in.txt", "r", stdin)
 23 #define FOUT freopen("out.txt", "w", stdout)
 24 #define rep(i, a, b) for(int i = a; i <= b; i ++)
 25
 26 template<class T> T CMP_MIN(T a, T b) { return a < b; }
 27 template<class T> T CMP_MAX(T a, T b) { return a > b; }
 28 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
 29 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
 30 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
 31 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
 32
 33 //typedef __int64 LL;
 34 typedef long long LL;
 35 const int MAXN = 10010;
 36 const int MAXM = 20010;
 37 const double eps = 1e-4;
 38
 39
 40 const int dx[4] = {0, 1, 0, -1};
 41 const int dy[4] = {1, 0, -1, 0};
 42 int T, N, M, K, B, ans = 0;
 43
 44 /*******************************************************************/
 45 struct Edge {
 46     int to, cap, flow, cost, next;
 47     Edge(){}
 48     Edge(int _n, int _v, int _c, int _f, int _cost){
 49         next = _n; to = _v; cap = _c;
 50         flow = _f; cost = _cost;
 51     }
 52 };
 53
 54 struct MCMF
 55 {
 56     int n, m, src, des;
 57     int head[MAXN], tot;
 58     Edge edges[MAXM];
 59     int inq[MAXN];
 60     int d[MAXN];
 61     int p[MAXN];
 62     int a[MAXN];
 63
 64     void init(int n) {
 65         this->tot = 0;
 66         this->n = n;
 67         mem1(head);
 68     }
 69
 70     void add_edge(int from, int to, int cap, int cost) {
 71         edges[tot] = Edge(head[from], to, cap, 0, cost);
 72         head[from] = tot ++;
 73         edges[tot] = Edge(head[to], from, 0, 0, -cost);
 74         head[to] = tot ++;
 75     }
 76
 77     bool bellman_ford(int s, int t, int& flow) {
 78         for(int i = 0; i < n; i ++) {
 79             d[i] = INF;
 80             inq[i] = 0;
 81         }
 82         d[s] = 0; inq[s] = 1;
 83         p[s] = 0; a[s] = INF;
 84
 85         queue<int>Q;
 86         Q.push(s);
 87         while(!Q.empty()) {
 88             int u = Q.front(); Q.pop();
 89             inq[u] = false;
 90             for(int i = head[u]; i != -1; i = edges[i].next) {
 91                 int v = edges[i].to;
 92                 if(edges[i].cap > edges[i].flow && d[v] > d[u] + edges[i].cost) {
 93                     d[v] = d[u] + edges[i].cost;
 94                     p[v] = i;
 95                     a[v] = min(a[u], edges[i].cap - edges[i].flow);
 96                     if(!inq[v]) {
 97                         Q.push(v);
 98                         inq[v] = 1;
 99                     }
100                 }
101             }
102         }
103         if(d[t] >= 0) return false;
104
105         flow += a[t];
106         ans += d[t] * a[t];
107
108         int u = t;
109         while(u != s) {
110             edges[p[u]].flow += a[t];
111             edges[p[u]^1].flow -= a[t];
112             u = edges[p[u]^1].to;
113         }
114         return true;
115     }
116
117     int min_cost(int s, int t) {
118         int flow = 0;
119         while(bellman_ford(s, t, flow));
120         return ans;
121     }
122
123 };
124 /***************************************************************/
125
126 int idx(int i, int j) {
127     return (i - 1) * M + j;
128 }
129
130 int ok(int i, int j) {
131     return (i >= 1 && i <= N && j >= 1 && j <= M);
132 }
133
134
135 MCMF mcmf;
136
137 int main()
138 {
139     //FIN;
140     cin >> T;
141     rep (t, 1, T) {
142         scanf("%d %d %d", &N, &M, &K);
143         mcmf.init(N * M + 2);
144         mcmf.src = 0; mcmf.des = N * M + 1; ans = 0;
145         rep (i, 1, N) rep (j, 1, M) {
146             scanf("%d", &B);
147             ans += B * B;
148             if(i % 2 == j % 2) rep (k, 1, K) {
149                 mcmf.add_edge(mcmf.src, idx(i, j), 1, 2 * k - 1 - 2 * B);
150                 rep (k, 0, 3) if(ok(i + dx[k], j + dy[k])) {
151                     mcmf.add_edge(idx(i, j), idx(i + dx[k], j + dy[k]), INF, 0);
152                 }
153             }
154             else rep (k, 1, K) {
155                 mcmf.add_edge(idx(i, j), mcmf.des, 1, 2 * k - 1 - 2 * B);
156             }
157         }
158         printf("Case %d: %d\n", t, mcmf.min_cost(mcmf.src, mcmf.des));
159     }
160     return 0;
161 }
时间: 2024-11-20 03:28:07

FZU2143Board Game(最小费用流)的相关文章

HDU 3488Tour(网络流之最小费用流)

题目地址:hdu3488 这题跟上题基本差不多啊....详情请戳这里. 另外我觉得有要改变下代码风格了..终于知道了为什么大牛们的代码的变量名都命名的那么长..我决定还是把源点与汇点改成source和sink吧..用s和t太容易冲突了...于是如此简单的一道题调试到了现在..sad... 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #

【bzoj1834】[ZJOI2010]network 网络扩容 最大流+最小费用流

题目描述 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入 输入文件的第一行包含三个整数N,M,K,表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边. 输出 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 样例输入 5 8 2 1 2 5 8 2 5 9

poj2135 最小费用流

添加超级源点(与点1之间的边容量为2,权值为0)和超级汇点(与点N之间的边容量为2,权值为0),求流量为2的最小费用流.注意是双向边. #include <iostream> #include <cstdio> #include <vector> #include <queue> using namespace std; const long long INF = 0x3f3f3f3f3f3f3f3f; typedef long long ll; typed

HDU 1533 Going Home(最小费用流)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3278    Accepted Submission(s): 1661 Problem Description On a grid map there are n little men and n houses. In each unit time, every

HDU 1853Cyclic Tour(网络流之最小费用流)

题目地址:HDU1853 费用流果然好神奇..还可以用来判断环...如果每个点都是环的一部分而且每个点只能用到一次的话,那每个点的初度入度都是1,这就可以利用网络流来解决,只要拆点令其流量为1,就限制了每个点只能用一次,每次左边的连到右边的,就相当于左边点的一次初度和右边的点的一次入度,很容易想象出来.最后只要判断总流量是否为n即可,因为如果总流量为n的话,说明每个点都出了一次度,每个点都入了一次度,而且由于拆点的流量限制,充分说明了每个点的初度入度都是1.进而说明了每个点都在环里.然后输出最后

POJ 2135.Farm Tour 最小费用流

Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17307   Accepted: 6687 Description When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of

Going Home (hdu 1533 最小费用流)

集训的图论都快结束了,我才看懂了最小费用流,惭愧啊. = = 但是今天机械键盘到了,有弄好了自行车,好高兴\(^o^)/~ 其实也不是看懂,就会套个模板而已.... 这题最重要的就是一个: 多组输入一定要写个init()函数清空,并且输入的时候每次都要调用init() #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include &

POJ 3422 矩阵取数 最小费用流拆点+负边

Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9153   Accepted: 3696 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka mo

POJ 2195 一人一房 最小费用流 建图 水题

Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 21010   Accepted: 10614 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertica