题目:
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