HDU 4862 Jump(最大k路径覆盖 费用流)
题意:一个n*m的矩阵,需要遍历所有点,从起点出发每次只可向右或向下跳,若到达位置的数字与上一步的数字相同,则获得该数字大小的能量;
否则消耗能量:哈密顿距离减1;求可获得的最大能量;
思路:网络流之最大k路径覆盖。
源点向n*m(X图)各点建流量为1,费用为0的边;
n*m(Y图)各点向汇点建流量为1,费用为0的边;
新增一个起点;
源点向起点建流量为k,费用为0的边;起点向各点建流量1,费用为0的边;
n*m各点间建边;
建好图后跑最小费用最大流,如果满流则存在解,否则不存在;最小费用的相反数就是所能够获得的最大能量;
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; const int MAXN = 1010; const int MAXM = 10010; const int INF = 0x3f3f3f3f; struct Edge { int to,next,cap,flow,cost; }edge[MAXM]; int head[MAXN],tol; int pre[MAXN],dis[MAXN]; bool vis[MAXN]; int N; void init(int n) { N = n; tol = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int cap,int cost) { edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s,int t) { queue<int>q; for(int i = 0;i < N;i++) { dis[i] = INF; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && dis[v] > dis[u] +edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if(!vis[v]) { vis[v] = true; q.push(v); } } } } if(pre[t] == -1)return false; else return true; } int minCostMaxflow(int s,int t,int &cost) { int flow = 0; cost = 0; while(spfa(s,t)) { int Min = INF; for(int i = pre[t];i != -1 ;i = pre[edge[i^1].to]) { if(Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; } for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) { edge[i].flow += Min; edge[i^1].flow -= Min; cost += edge[i].cost*Min; } flow += Min; } return flow; } int n,m,k; char str[12][12]; void solve() { init(2*n*m + 3); int start = 2*n*m; int end = 2*n*m+2; addedge(start,start+1,k,0); for(int i = 0;i < n;i++) for(int j = 0;j < m;j++) { addedge(start,2*(i*m+j),1,0); addedge(2*(i*m+j)+1,end,1,0); addedge(start+1,2*(i*m+j)+1,1,0); for(int y = j+1;y < m;y++) //向右跳 { if(str[i][y] == str[i][j]) addedge(2*(i*m+j),2*(i*m+y)+1,1,-(str[i][j]-'0')+y-j-1); else addedge(2*(i*m+j),2*(i*m+y)+1,1,y-j-1); } for(int x = i+1; x < n;x++)//向下跳 { if(str[x][j] == str[i][j]) addedge(2*(i*m+j),2*(x*m+j)+1,1,-(str[i][j]-'0')+x-i-1); else addedge(2*(i*m+j),2*(x*m+j)+1,1,x-i-1); } } int cost; int flow = minCostMaxflow(start,end,cost); if(flow != n*m)printf("-1\n"); else printf("%d\n",-cost); } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; scanf("%d",&T); int iCase = 0; while(T--) { iCase++; scanf("%d%d%d",&n,&m,&k); for(int i = 0;i < n;i++) scanf("%s",str[i]); printf("Case %d : ",iCase); solve(); } return 0; }
有些梦想现在不去实现,以后就再也没机会了!!