HDU 4862 Jump (2014-多校1-1002,最小K路径覆盖,最小费用最大流)

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4862

题意:

给你一个n*m的矩阵,填充着0-9的数字,每次能从一个点出发,到它的右边或者下边的点,花费为|x1-x2|+|y1-y2|-1,如果跳跃的起点和终点的数字相同,则获得这个数字的收益,不能走已经走过的点

有K次重新选择起点的机会

如果可以走遍所有点,则输出最大的价值(收益-花费)

否则,输出-1

方法:

最小K路径覆盖,最小费用最大流

建图:

每个点拆为2点:X部和Y部,(a,b)表示流量a,费用b

源点与X部每个点连(1,0)的边

Y部每个点与汇点连(1,0)的边

X部的点如果可以到Y部的点,则连(1,花费-收益)的边

源点与一个新点连(k,0)的边,新点与Y部每个点连(1,0)的边

结果:

如果满流,则输出0-费用

否则,输出-1

代码:

  1 // #pragma comment(linker, "/STACK:102400000,102400000")
  2 #include <cstdio>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <set>
  8 #include <list>
  9 #include <map>
 10 #include <iterator>
 11 #include <cstdlib>
 12 #include <vector>
 13 #include <queue>
 14 #include <stack>
 15 #include <algorithm>
 16 #include <functional>
 17 using namespace std;
 18 typedef long long LL;
 19 #define ROUND(x) round(x)
 20 #define FLOOR(x) floor(x)
 21 #define CEIL(x) ceil(x)
 22 // const int maxn = 210;
 23 // const int maxm = 200010;
 24 // const int inf = 0x3f3f3f3f;
 25 const LL inf64 = 0x3f3f3f3f3f3f3f3fLL;
 26 const double INF = 1e30;
 27 const double eps = 1e-6;
 28 const int P[4] = {0, 0, -1, 1};
 29 const int Q[4] = {1, -1, 0, 0};
 30 const int PP[8] = { -1, -1, -1, 0, 0, 1, 1, 1};
 31 const int QQ[8] = { -1, 0, 1, -1, 1, -1, 0, 1};
 32
 33 /**
 34 *最小(大)费用最大流:SPFA增广路($O(w*O(SPFA))$)
 35 *最大费用:费用取反addEdge(,,,-cost);
 36 *输入:图(链式前向星),n(顶点个数,包含源汇),s(源),t(汇)
 37 *输出:minCostMaxflow(int s, int t, int &cost)返回流量, cost为费用
 38 *打印路径方法:按反向边(i&1)的flow 找,或者按边的flow找
 39 */
 40 const int maxn = 210;
 41 const int maxm = 200010;
 42 const int inf = 0x3f3f3f3f;
 43 struct Edge
 44 {
 45     int u, v;
 46     int cap, flow;
 47     int cost;
 48     int next;
 49 } edge[maxm];
 50 int head[maxn], en; //需初始化
 51 int n, m;
 52 int st, ed;
 53 bool vis[maxn];
 54 int pre[maxn], dis[maxn];
 55 void addse(int u, int v, int cap, int flow, int cost)
 56 {
 57     edge[en].u = u;
 58     edge[en].v = v;
 59     edge[en].cap = cap;
 60     edge[en].flow = flow;
 61     edge[en].cost = cost;
 62     edge[en].next = head[u];
 63     head[u] = en++;
 64 }
 65 void adde(int u, int v, int cap, int cost)
 66 {
 67     addse(u, v, cap, 0, cost);
 68     addse(v, u, 0, 0, -cost); //注意加反向0 边
 69 }
 70 bool spfa(int s, int t)
 71 {
 72     queue<int>q;
 73     for (int i = 0; i < n; i++)
 74     {
 75         dis[i] = inf;
 76         vis[i] = false;
 77         pre[i] = -1;
 78     }
 79     dis[s] = 0;
 80     vis[s] = true;
 81     q.push(s);
 82     while (!q.empty())
 83     {
 84         int u = q.front();
 85         q.pop();
 86         vis[u] = false;
 87         for (int i = head[u]; i != -1; i = edge[i].next)
 88         {
 89             int v = edge[i].v;
 90             if (edge[i].cap > edge[i].flow &&
 91                     dis[v] > dis[u] + edge[i].cost )
 92             {
 93                 dis[v] = dis[u] + edge[i].cost;
 94                 pre[v] = i;
 95                 if (!vis[v])
 96                 {
 97                     vis[v] = true;
 98                     q.push(v);
 99                 }
100             }
101         }
102     }
103     if (pre[t] == -1)return false;
104     else return true;
105 }
106 int minCostMaxflow(int s, int t, int &cost)//返回流量, cost为费用
107 {
108     int flow = 0;
109     cost = 0;
110     while (spfa(s, t))
111     {
112         int Min = inf;
113         for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].v])
114         {
115             if (Min > edge[i].cap - edge[i].flow)
116                 Min = edge[i].cap - edge[i].flow;
117         }
118         for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].v])
119         {
120             edge[i].flow += Min;
121             edge[i ^ 1].flow -= Min;
122             cost += edge[i].cost * Min;
123         }
124         flow += Min;
125     }
126     return flow;
127 }
128 int N, M, K;
129 int kase;
130 int mtx[maxn][maxn];
131 int disxy(int x1, int y1, int x2, int y2)
132 {
133     return abs(x1 - x2) + abs(y1 - y2) - 1;
134 }
135 void build()
136 {
137     n = 3 + N * M * 2;
138     st = 0, ed = 1;
139     for (int i = 0; i < N; i++)
140     {
141         for (int j = 0; j < M; j++)
142         {
143             adde(st, i * M + j + 3, 1, 0);
144         }
145     }
146     adde(st, 2, K, 0);
147     for (int i = 0; i < N; i++)
148     {
149         for (int j = 0; j < M; j++)
150         {
151             adde(2, i * M + j + N * M + 3, 1, 0);
152             adde(i * M + j + N * M + 3, ed, 1, 0);
153         }
154     }
155     for (int i = 0; i < N; i++)
156     {
157         for (int j = 0; j < M; j++)
158         {
159             for (int h = i + 1; h < N; h++)
160             {
161                 if (mtx[i][j] == mtx[h][j])
162                 {
163                     adde(i * M + j + 3, h * M + j + N * M + 3, 1, h - i - 1 - mtx[i][j]);
164                     // cout << i << " " << j << " " << h << " " << j << endl;
165                 }
166                 else
167                 {
168                     adde(i * M + j + 3, h * M + j + N * M + 3, 1, h - i - 1);
169                 }
170             }
171             for (int h = j + 1; h < M; h++)
172             {
173                 if (mtx[i][j] == mtx[i][h])
174                 {
175                     adde(i * M + j + 3, i * M + h + N * M + 3, 1, h - j - 1 - mtx[i][j]);
176                     // cout << i << " " << j << " " << i << " " << h << endl;
177                 }
178                 else
179                 {
180                     adde(i * M + j + 3, i * M + h + N * M + 3, 1, h - j - 1);
181                 }
182             }
183         }
184     }
185 }
186 void init()
187 {
188     memset(head, -1, sizeof(head));
189     en = 0;
190     kase++;
191 }
192 void input()
193 {
194     scanf("%d%d%d", &N, &M, &K);
195     for (int i = 0; i < N; i++)
196     {
197         char str[maxn];
198         scanf("%s", str);
199         for (int j = 0; j < M; j++)
200         {
201             mtx[i][j] = str[j] - ‘0‘;
202         }
203     }
204 }
205 void debug()
206 {
207     //
208 }
209 void solve()
210 {
211     build();
212     int cost;
213     int flow = minCostMaxflow(st, ed, cost);
214     // cout << "flow,cost: " << flow << " " << cost << endl;
215     if (flow == N * M)
216     {
217         printf("Case %d : %d\n", kase, -cost);
218     }
219     else
220     {
221         printf("Case %d : %d\n", kase, -1);
222     }
223 }
224 void output()
225 {
226     //
227 }
228 int main()
229 {
230     // int size = 256 << 20; // 256MB
231     // char *p = (char *)malloc(size) + size;
232     // __asm__("movl %0, %%esp\n" :: "r"(p));
233
234     // std::ios_base::sync_with_stdio(false);
235 #ifndef ONLINE_JUDGE
236     freopen("in.cpp", "r", stdin);
237 #endif
238
239     kase = 0;
240     int T;
241     scanf("%d", &T);
242     while (T--)
243     {
244         init();
245         input();
246         solve();
247         output();
248     }
249     return 0;
250 }

HDU 4862

HDU 4862 Jump (2014-多校1-1002,最小K路径覆盖,最小费用最大流)

时间: 2024-10-19 02:06:00

HDU 4862 Jump (2014-多校1-1002,最小K路径覆盖,最小费用最大流)的相关文章

HDU 4862 Jump (最小K路径覆盖)

HDU 4862 Jump 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4862 题意:给定一个N*M的矩阵,矩阵里面为0~9的数字.现在规定从一个点可以跳到它正下方和正右方的点,花费的费用为曼哈顿距离 - 1.如果在跳的过程中,两个点的数字相同,那么将得到该点的数字.规定可以从任意点开始跳,每个点只能经过1次.最多可以选择K个点来作为起点进行跳跃.问能否经过所有的点,如果可以,那么花费的费用是多少. 思路: 如果是最小路径覆盖,那么很容易构造图.但

HDU 4862 Jump(最小K路径覆盖)

输入一个n×m网格图,每个结点的值为0-9,可以从任意点出发不超过k次,走完每个点且仅访问每个结点一次,问最终的能量最大值.不可全部走完的情况输出-1. 初始能量为0. 而结点(x,y)可以跳跃到结点(x,y+dy)或(x+dx,y).消耗能量为跳跃前后结点的曼哈顿距离 - 1 .若跳跃前后的结点的值相等,能量加上那个值. 具体建图可以参考这里http://blog.sina.com.cn/s/blog_6bddecdc0102uy9g.html 最小K路径覆盖其实在之前是见过的打过的,不过这次

HDU 4862 Jump 最小k路径覆盖 费用流

gg... 题意: 给定n*m的矩阵 选<=k个起点 每个起点可以向右或向下跳任意步 花费是2点间的曼哈顿距离 若2个格子的数字一样 则赚取格子上的数字的价值 问:遍历整个图的最小花费 若不能遍历则输出-1 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <set> #in

HDU 4862 Jump(更多的联合培训学校1)(最小费用最大流)

职务地址:pid=4862">HDU4862 最小费用流做的还是太少. 建图想不出来. . . 直接引用官方题解的话吧... 最小K路径覆盖的模型.用费用流或者KM算法解决,构造二部图,X部有N*M个节点.源点向X部每一个节点连一条边,流量1,费用0,Y部有N*M个节点,每一个节点向汇点连一条边.流量1,费用0.假设X部的节点x能够在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量.流量1,再在X部添加一个新的节点,表示能够从随意节点出发K

hdu 4862 KM算法 最小K路径覆盖的模型

http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过所有的点一次并且仅仅一次, 建图是问题: 我自己最初就把n*m 个点分别放入X集合以及Y集合,再求最优匹配,然后连样例都过不了,而且其实当时解释不了什么情况下不能得到结果,因为k此这个条件相当于没用上... 建图方法: 1.X集合和Y集合都放入n*m+k个点,X中前n*m个点和Y中前n*m个点之间,如果格子里的值相等,权就是(收益-耗费),不等就是(-耗费),因为要的是最大收益

HDU 4862 Jump(多校联合训练1)(最小费用最大流)

题目地址:HDU4862 最小费用流做的还是太少.建图想不出来... 直接引用官方题解的话吧... 最小K路径覆盖的模型,用费用流或者KM算法解决,构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0,Y部有N*M个节点,每个节点向汇点连一条边,流量1,费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量,流量1,再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边,费用0,流量K,这个点向

HDU 4862 Jump 费用流

又是一个看了题解以后还坑了一天的题…… 结果最后发现是抄代码的时候少写了一个负号. 题意: 有一个n*m的网格,其中每个格子上都有0~9的数字.现在你可以玩K次游戏. 一次游戏是这样定义的: 你可以选任意之前没有走过的格子作为起点.然后走任意步,其中每一步你可以向右或者向下走任意格.假如从(x1, y1)走到(x2, y2)需要花费能量|x1-x2|+|y1-y2|-1,如果这一步和上一步格子的数字相同,那么可以获得格子上相应数字的能量.能量可以为负值. 问你,在K次以内走完所以格子最多能得到多

HDU 4862 JUMP 最小费用最大流

2014 多校的B题,由于我不怎么搞图论,当时碰到这个题目,我怎么想都没往网络流方面弄,不过网络流真的是个好东西,对于状态多变,无法用动规或者数据结构来很好表示的时候,非常有用 这个题目要求每个点一定要访问到,并且每次访问的是没访问过的点,跳跃的方向为向右或者向下. 建图的时候,分成二分图,从一个超级源点向x部分建cap为1 cost为0的点,对所以可到达的点从x到y建cap为1,cost根据题目算出来,不过要算负值,因为我们要求得实际是最大费用,最后对结果求相反数即可.所有y部分的点对超级汇点

hdu 4862 Jump 上下界费用流

对于每个点拆点成为两个点a,b,连接a到b的上界为1,下界为1的边,保证用过一次且仅一次. 然后若点u可到达点v,则连接即可.建成了一个上下界网络,将下界拆出去,求最大费用最大流就好. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=800; const int MAXE=200000; const int inf=1<<3