hdu4862 费用流(不错)
生活随笔
收集整理的這篇文章主要介紹了
hdu4862 费用流(不错)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
? ? ? 給你一個矩陣,你最多可以選擇k條路線,k條路線的起點隨意,每次行走的距離隨意,但是只能往右或者下走,走過的點不能再走,而且每一步如果a->b,如果a和b的權值s相等那么就可以獲得s這么多能量,每一步花費的能量是|x1 - x2| + |y1 - y2| - 1,最后問你吧所有點都遍歷后獲得的最大能量是多少。
思路:
? ? ? 每個點只能走一次,最多可以選擇k條路徑,要求全走完的最大,顯然是費用流,我寫的是最大費用最大流,(最小費用最大流也行,就是正負的問題)下面說建邊。
? (1) 首先虛擬出來三個點,源點s,終點e,超級遠點ss。
?*(2) 拆點 a -> a' ?流量1,費用INF //每個點只能訪問一次,INF是為了讓所有的點都訪?問到,這個是關鍵,如果 ? ? 是最消費用流的話可以使 -INF?
? (3) ss -> s 費用0流量k ?//限制路徑條數
? (4) s -> a ?費用0流量1 ?// 每一個點都可以當路徑起點
? (5) a' -> b 費用 可獲得價值-花費 流量是1 // 每個點讓他右和下的所有點建邊
? (6) a' -> e 費用0,流量1 //每個點都可以做路徑終點
?*(7) s -> e ?費用0,流量INF // 題目說k可以不全用,排除強制用k條導致的錯誤
? ? ? 給你一個矩陣,你最多可以選擇k條路線,k條路線的起點隨意,每次行走的距離隨意,但是只能往右或者下走,走過的點不能再走,而且每一步如果a->b,如果a和b的權值s相等那么就可以獲得s這么多能量,每一步花費的能量是|x1 - x2| + |y1 - y2| - 1,最后問你吧所有點都遍歷后獲得的最大能量是多少。
思路:
? ? ? 每個點只能走一次,最多可以選擇k條路徑,要求全走完的最大,顯然是費用流,我寫的是最大費用最大流,(最小費用最大流也行,就是正負的問題)下面說建邊。
? (1) 首先虛擬出來三個點,源點s,終點e,超級遠點ss。
?*(2) 拆點 a -> a' ?流量1,費用INF //每個點只能訪問一次,INF是為了讓所有的點都訪?問到,這個是關鍵,如果 ? ? 是最消費用流的話可以使 -INF?
? (3) ss -> s 費用0流量k ?//限制路徑條數
? (4) s -> a ?費用0流量1 ?// 每一個點都可以當路徑起點
? (5) a' -> b 費用 可獲得價值-花費 流量是1 // 每個點讓他右和下的所有點建邊
? (6) a' -> e 費用0,流量1 //每個點都可以做路徑終點
?*(7) s -> e ?費用0,流量INF // 題目說k可以不全用,排除強制用k條導致的錯誤
? ? ? 這樣就行了,還有就是說明下這個題目如果可以覆蓋的話根本不存在負的答案,題目的那句話是誤導人的,如果出現負的,那么就直接是無解的,因為ans = mclow - n * m *?INF,INF很大,只要有一個格子沒被覆蓋過,那么abs就直接是負值了。
#include<stdio.h> #include<string.h> #include<queue>#define N_node 220 #define N_edge 33000 #define INF 10000000 using namespace std;typedef struct {int from ,to ,next ,cost ,flow; }STAR;STAR E[N_edge]; int list[N_node] ,tot; int s_x[N_node]; int mer[N_edge];void add(int a ,int b ,int c ,int d) {E[++tot].from = a;E[tot].to = b;E[tot].cost = c;E[tot].flow = d;E[tot].next = list[a];list[a] = tot;E[++tot].from = b;E[tot].to = a;E[tot].cost = -c;E[tot].flow = 0;E[tot].next = list[b];list[b] = tot; }bool spfa(int s ,int t ,int n) {for(int i = 0 ;i <= n ;i ++)s_x[i] = -1000000000;int mark[N_node] = {0};s_x[s] = 0 ,mark[s] = 1;queue<int>q;q.push(s);memset(mer ,255 ,sizeof(mer));while(!q.empty()){int xin ,tou;tou = q.front();q.pop();mark[tou] = 0;for(int k = list[tou] ;k ;k = E[k].next){xin = E[k].to;if(E[k].flow && s_x[xin] < s_x[tou] + E[k].cost){mer[xin] = k;s_x[xin] = s_x[tou] + E[k].cost;if(!mark[xin]) {mark[xin] = 1;q.push(xin);}}}}return mer[t] != -1; }int M_C_Flow(int s ,int t ,int n ,int nn ,int mm) {int maxcost = 0 ,minflow ,maxflow = 0;while(spfa(s ,t ,n)){maxflow = INF;for(int i = mer[t] ;i + 1 ;i = mer[E[i].from]){if(minflow > E[i].flow)minflow = E[i].flow;}for(int i = mer[t] ;i + 1 ;i = mer[E[i].from]){E[i].flow -= minflow;E[i^1].flow += minflow;maxcost += E[i].cost * minflow;}maxflow += minflow;}return maxcost; }int abss(int x) {return x < 0 ? -x : x; }int main () {int map[15][15];int n ,m ,k ,i ,cas = 1 ,t ,j;scanf("%d" ,&t);while(t--){scanf("%d %d %d" ,&n ,&m ,&k);char tmp[15];for(i = 1 ;i <= n ;i ++){scanf("%s" ,tmp);for(j = 1 ;j <= m ;j ++)map[i][j] = tmp[j-1] - '0';}memset(list ,0 ,sizeof(list)) ,tot = 1;for(i = 1 ;i <= n ;i ++)for(j = 1 ;j <= m ;j ++){int now = (i - 1) * m + j;add(now ,now + n * m ,INF ,1);}int s = 0 ,ss = n * m * 2 + 1 ,e = n * m * 2 + 2;add(s ,ss ,0 ,k);for(i = 1 ;i <= n ;i ++)for(j = 1 ;j <= m ;j ++){int now = (i - 1) * m + j;add(ss ,now ,0 ,1);add(now + n * m ,e ,0 ,1);for(k = i + 1 ;k <= n ;k ++){int to = (k - 1) * m + j;int dis = abss(i - k) - 1;if(map[i][j] == map[k][j])add(now + n * m ,to ,map[i][j] - dis,1);else add(now + n * m ,to ,0 - dis ,1);}for(k = j + 1 ;k <= m ;k ++){int to = (i - 1) * m + k;int dis = abss(j - k) - 1;if(map[i][j] == map[i][k])add(now + n * m ,to ,map[i][j] - dis,1);else add(now + n * m ,to ,0 - dis ,1);}}add(ss ,e ,0 ,INF);int ans = M_C_Flow(s ,e ,e ,n ,m) - n * m * INF;if(ans < 0) ans = -1;printf("Case %d : " ,cas ++);printf("%d\n" ,ans);}return 0; }
總結
以上是生活随笔為你收集整理的hdu4862 费用流(不错)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu4861 找规律了
- 下一篇: hdu4864 贪心