Suppose an image has R rows and C columns. We can assign each of the pixel a number ranging from 1 to R * C depending on its scan-line order. We define n = R * C and the energy function is in the form of
where
> j in N(i) means that the pixel j is in the left, right, top or bottom neighbor of pixel i;
> the integer pi (0 <= pi <= 255) is the gray level of the pixel i;
> xi (xi in {0, 1}) is the assigned label to the pixel i; and
> the integers v0 and v1 (0 <= v0, v1 <= 255) are the prior estimation of the gray level of the pixels labeled 0 and 1 respectively.
Input Description
Standard input will contain multiple test cases. The first line of the input is a single integer T (1 <= T <= 10) which is the number of test cases. T test cases follow, each preceded by a single blank line.
The first line of each test case contains four integers R, C (2 <= R, C <= 20), v0 and v1. The following R lines contain C integers each, which are the gray level of the pixels. The proper ranges are shown in the problem description.
Output Description
Results should be directed to standard output. Start each case with "Case #:" on a single line, where # is the case number starting from 1. Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.
For each case, output the minimized energy value in a single line.
Sample Input
3
2 2 24 91
236 224
250 248
3 3 144 194
44 33 24
92 4 227
47 63 35
2 4 111 19
65 86 109 153
115 186 146 112
Sample Output
Case 1:
594
Case 2:
893
Case 3:
230
Source: Asia 2005, Hangzhou (Mainland China), Preliminary
如果知道最小割模型可以求解题目函数最值,这道题就很简单了。
碰巧我知道这个应用 ,但找点函数(x-1) * C + y写成(x-1) * R + y WA了一次,真是醉了! o(╯□╰)o
AC这道题后(一定要理解最小割模型的意义),推荐一道比它要难的题(需要先构建函数)点我
题意:给出一个R*C的矩阵,定义n=R*C。
把矩阵转化成数组p[],则矩阵中元素Map[i][j] 在p[]中下标是(i-1) * C+j。
1,xi(1 <= i <=n)的值为0或1;
2,已经给出v0和v1,
3,j 属于N(i)——表示j是i在矩阵中邻近的元素(上、下、左、右)。
现在让你求函数E的最小值。
最小割模型的应用,不多说了。
直接说建图:
设置超级源点S,超级汇点T。我们定义S与x[i]为1的集合相连,x[i]为0的集合和T相连。
1,x[i]选择1(不选0,割去x[i]选0这条边,代价为|p[i] - v1|),i -> T建边,容量为|p[i] - v1|;
2,x[i]选择0(不选1,割去x[i]选1这条边,代价为|p[i] - v0|),S - > i建边,容量为|p[i] - v0|;
3,x[i]选1且x[j]选0(i和j不能在一个集合,割去i和j这条边,代价为|p[i] - p[j]|),i - > j建边,容量为|p[i] - p[j]|。
4,x[i]选0且x[j]选1,建边同3。
求出的最小割就是函数最小值。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define MAXN 500 #define MAXM 10000 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, cap, flow, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int dist[MAXN], cur[MAXN]; bool vis[MAXN]; int Map[21][21]; int R, C, v0, v1; int getpoint(int x, int y) { return (x-1) * C + y;//犯二了 醉了。。。 } void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int w) { Edge E1 = {u, v, w, 0, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } bool judge(int x, int y) { return x > 0 && x <= R && y > 0 && y <= C; } int S, T;//超级源点 超级汇点 int sum; void getMap() { scanf("%d%d%d%d", &R, &C, &v0, &v1); init(); sum = 0; for(int i = 1; i <= R; i++) { for(int j = 1; j <= C; j++) scanf("%d", &Map[i][j]), sum += Map[i][j]; } S = 0, T = getpoint(R, C) + 1; int move[2][2] = {0,1, 1,0}; for(int i = 1; i <= R; i++) { for(int j = 1; j <= C; j++) { int u = getpoint(i, j); addEdge(u, T, abs(Map[i][j]-v1));//选择1 addEdge(S, u, abs(Map[i][j]-v0));//选择0 for(int k = 0; k < 2; k++)//只选取右边两个避免重复 建边 { int x = i + move[k][0]; int y = j + move[k][1]; if(!judge(x, y)) continue;//越界 int v = getpoint(x, y); addEdge(u, v, abs(Map[i][j]-Map[x][y]));//选1 -> 选0 addEdge(v, u, abs(Map[i][j]-Map[x][y])); } } } } bool BFS(int s, int t) { queue<int> Q; memset(dist, -1, sizeof(dist)); memset(vis, false, sizeof(vis)); dist[s] = 0; vis[s] = true; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(!vis[E.to] && E.cap > E.flow) { dist[E.to] = dist[u] + 1; if(E.to == t) return true; vis[E.to] = true; Q.push(E.to); } } } return false; } int DFS(int x, int a, int t) { if(x == t || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next) { Edge &E = edge[i]; if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap-E.flow), t)) > 0) { edge[i].flow += f; edge[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t) { int flow = 0; while(BFS(s, t)) { memcpy(cur, head, sizeof(head)); flow += DFS(s, INF, t); } return flow; } int main() { int t, k = 1; scanf("%d", &t); while(t--) { getMap(); printf("Case %d:\n%d\n", k++, Maxflow(S, T)); if(t) printf("\n"); } return 0; }