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路径覆盖其实在之前是见过的打过的,不过这次又不会了,说明之前不牢固。。。要认真点,没什么时间浪费了。
平时在求二分图的无权的最小覆盖的时候,用的就是 n - 最大匹配
那个从源点连流量为K,费用为0的边到的“那个结点”,实际上就上虚拟前驱。。。因为X集合其实就是Y集合的前驱。而起点的前驱就是没有前驱,即“那个结点”。
然后如果满流量的话,说明所有结点都走了一遍。
模板是找JM伙伴要的。。。据说伙伴是参考KH师兄的=。=
其实最近经常问JM题。。。感觉自己退步了=。=要加油!!!
1 #include<cstdio> 2 #include<set> 3 #include<cstring> 4 #include<iostream> 5 #include<stdlib.h> 6 #include<vector> 7 #include<algorithm> 8 #include<queue> 9 #include<cmath> 10 using namespace std; 11 12 13 #define maxn 222 14 #define maxe 30000 15 #define inf 0x3f3f3f3f 16 17 struct Edge{ 18 int u, v, nxt, cap, cost; 19 }edge[maxe]; 20 int head[maxn]; 21 22 struct MinCostMaxFlow{ 23 queue<int> que; 24 int add; // edges number 25 int vn; // total vertex number 26 int cost[maxn], in[maxn], pre[maxn]; 27 bool vis[maxn]; 28 void init(int sz){ 29 add = 0; vn = sz + 10; memset(head, -1, sizeof(head)); 30 while (!que.empty()) que.pop(); 31 } 32 void insert(int u, int v, int w, int c){// u, v, capacity, cost 33 edge[add].u = u; edge[add].v = v; edge[add].cap = w; edge[add].cost = c; 34 edge[add].nxt = head[u]; head[u] = add++; 35 edge[add].u = v; edge[add].v = u; edge[add].cap = 0; edge[add].cost = -c; 36 edge[add].nxt = head[v]; head[v] = add++; 37 } 38 bool spfa(int s, int e){ 39 memset(cost, 0x3f3f3f3f, sizeof(cost)); 40 memset(in, 0, sizeof(in)); 41 memset(vis, 0, sizeof(vis)); 42 cost[s] = 0; pre[s] = -1; 43 que.push(s); vis[s] = true; in[s]++; 44 while (!que.empty()){ 45 int u = que.front(); que.pop(); 46 vis[u] = false; 47 for (int i = head[u]; i != -1; i = edge[i].nxt){ 48 int v = edge[i].v; 49 if (edge[i].cap > 0 && cost[v] > cost[u] + edge[i].cost){ 50 cost[v] = cost[u] + edge[i].cost; pre[v] = i; 51 if (!vis[v]){ 52 que.push(v); vis[v] = true; in[v]++; 53 if (in[v] > vn) return false; 54 } 55 } 56 } 57 } 58 return cost[e] < inf; 59 } 60 void mincostmaxflow(int s, int e, int &mincost, int &maxflow){ 61 mincost = 0, maxflow = 0; 62 while (spfa(s, e)){ 63 int flow = inf; 64 for (int i = pre[e]; i != -1; i = pre[edge[i].u]){ 65 flow = min(flow, edge[i].cap); 66 } 67 maxflow += flow; 68 for (int i = pre[e]; i != -1; i = pre[edge[i].u]){ 69 edge[i].cap -= flow; 70 edge[i ^ 1].cap += flow; 71 } 72 mincost += cost[e] * flow; 73 } 74 } 75 }net; 76 77 int nm; 78 char ch[22][22]; 79 int main(){ 80 int t,n,m,k,ca=0; 81 scanf("%d",&t); 82 while(t--){ 83 scanf("%d%d%d",&n,&m,&k); 84 nm = n*m; 85 for(int i=0;i<n;++i)scanf("%s",ch[i]); 86 net.init(nm*2+3); 87 for(int i=0;i<n;++i){ 88 for(int j=0;j<m;++j){ 89 int u = i*m+j+1; 90 for(int k=i+1;k<n;++k){ 91 int v = k*m+j+1; 92 int tmp = -(k-i-1); 93 if(ch[i][j]==ch[k][j]) tmp+=ch[i][j]-'0'; 94 net.insert(u,nm+v,1,-tmp); 95 } 96 for(int k=j+1;k<m;++k){ 97 int v = i*m+k+1; 98 int tmp = -(k-j-1); 99 if(ch[i][j]==ch[i][k]) tmp+=ch[i][j]-'0'; 100 net.insert(u,nm+v,1,-tmp); 101 } 102 } 103 } 104 for(int i=nm+1;i<=nm*2;++i) net.insert(nm*2+1,i,1,0); 105 for(int i=1;i<=nm;++i) net.insert(0,i,1,0); 106 net.insert(0,nm*2+1,k,0); 107 for(int i=nm+1;i<=nm*2;++i)net.insert(i,nm*2+2,1,0); 108 int cost,flow; 109 net.mincostmaxflow(0,nm*2+2,cost,flow); 110 printf("Case %d : ",++ca); 111 if(flow==nm) printf("%d\n",-cost); 112 else puts("-1"); 113 } 114 return 0; 115 }