poj 3422 Kaka's Matrix Travels hdu 3376 matrix again 费用流
这两题有一个共同的特点,都是从矩阵的左上角走到右下角,求最大能获得的权值
不过poj 3422可以走k次
poj 3422
每个点走过一次后,这个点的权值就置零了,相当于经过一次后以后每次经过都没有费用了,所以每个点拆点后u->u' 建两条边
一条边容量为1 费用为负的点权
另一条边容量为INF,费用为0
另外如果一个点能到另一个点,还是老方法u'->v,容量为INF,费用为0;
最后要限制总流量为k,即建一个源点向1建一条容量为k,费用为0的边 n*n*2(最后一个点的出点) 向汇点连一条容量为k费用为0的边
最后求一下S、T的最小费用流即可
View Code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int sumFlow; const int MAXN = 720010; const int MAXM = 1000010; const int INF = 1000000000; struct Edge { int u, v, cap, cost; int next; }edge[MAXM<<2]; int NE; int head[MAXN], dist[MAXN], pp[MAXN]; bool vis[MAXN]; void init() { NE = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost; edge[NE].next = head[u]; head[u] = NE++; edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost; edge[NE].next = head[v]; head[v] = NE++; } bool SPFA(int s, int t, int n) { int i, u, v; queue <int> qu; memset(vis,false,sizeof(vis)); memset(pp,-1,sizeof(pp)); for(i = 0; i <= n; i++) dist[i] = INF; vis[s] = true; dist[s] = 0; qu.push(s); while(!qu.empty()) { u = qu.front(); qu.pop(); vis[u] = false; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].cap && dist[v] > dist[u] + edge[i].cost) { dist[v] = dist[u] + edge[i].cost; pp[v] = i; if(!vis[v]) { qu.push(v); vis[v] = true; } } } } if(dist[t] == INF) return false; return true; } int MCMF(int s, int t, int n) // minCostMaxFlow { int flow = 0; // 总流量 int i, minflow, mincost; mincost = 0; while(SPFA(s, t, n)) { minflow = INF + 1; for(i = pp[t]; i != -1; i = pp[edge[i].u]) if(edge[i].cap < minflow) minflow = edge[i].cap; flow += minflow; for(i = pp[t]; i != -1; i = pp[edge[i].u]) { edge[i].cap -= minflow; edge[i^1].cap += minflow; } mincost += dist[t] * minflow; } sumFlow = flow; // 题目需要流量,用于判断 return mincost; } int main() { int n,i,j,x,k; while(scanf("%d",&n)!=EOF) { scanf("%d",&k); init(); int S=0,T=n*n*2+1; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%d",&x); int u=(i-1)*n+j; addedge(u,u+n*n,INF,0); addedge(u,u+n*n,1,-x); if(i<n) addedge(u+n*n,u+n,INF,0); if(j<n) addedge(u+n*n,u+1,INF,0); } } addedge(S,1,k,0); addedge(n*n*2,T,k,0); printf("%d\n",-MCMF(S,T,T+1)); } }
View Code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int sumFlow; const int MAXN = 720010; const int MAXM = 1000010; const int INF = 1000000000; struct Edge { int u, v, cap, cost; int next; }edge[MAXM<<2]; int NE; int head[MAXN], dist[MAXN], pp[MAXN]; bool vis[MAXN]; void init() { NE = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost; edge[NE].next = head[u]; head[u] = NE++; edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost; edge[NE].next = head[v]; head[v] = NE++; } bool SPFA(int s, int t, int n) { int i, u, v; queue <int> qu; memset(vis,false,sizeof(vis)); memset(pp,-1,sizeof(pp)); for(i = 0; i <= n; i++) dist[i] = INF; vis[s] = true; dist[s] = 0; qu.push(s); while(!qu.empty()) { u = qu.front(); qu.pop(); vis[u] = false; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].cap && dist[v] > dist[u] + edge[i].cost) { dist[v] = dist[u] + edge[i].cost; pp[v] = i; if(!vis[v]) { qu.push(v); vis[v] = true; } } } } if(dist[t] == INF) return false; return true; } int MCMF(int s, int t, int n) // minCostMaxFlow { int flow = 0; // 总流量 int i, minflow, mincost; mincost = 0; while(SPFA(s, t, n)) { minflow = INF + 1; for(i = pp[t]; i != -1; i = pp[edge[i].u]) if(edge[i].cap < minflow) minflow = edge[i].cap; flow += minflow; for(i = pp[t]; i != -1; i = pp[edge[i].u]) { edge[i].cap -= minflow; edge[i^1].cap += minflow; } mincost += dist[t] * minflow; } sumFlow = flow; // 题目需要流量,用于判断 return mincost; } int main() { int n,i,j,x,k; while(scanf("%d",&n)!=EOF) { scanf("%d",&k); init(); int S=1,T=n*n*2; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%d",&x); int u=(i-1)*n+j; addedge(u,u+n*n,1,-x); addedge(u,u+n*n,k-1,0); if(i<n) addedge(u+n*n,u+n,INF,0); if(j<n) addedge(u+n*n,u+1,INF,0); } } if(k==0) { puts("0"); continue; } //addedge(S,1,k,0); //addedge(n*n*2,T,k,0); printf("%d\n",-MCMF(S,T,T)); } }
hdu 3376
这题注意开大空间啊,空间没开够错了好几次
因为每个点只能经过一次,立刻就联想到了拆点
源点有2的容量,汇点也有2的容量 即s-s'容量为2,费用为点权
建好图后求一次最小费用最大流即可
View Code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int sumFlow; const int MAXN = 720010; const int MAXM = 1000010; const int INF = 1000000000; struct Edge { int u, v, cap, cost; int next; }edge[MAXM<<2]; int NE; int head[MAXN], dist[MAXN], pp[MAXN]; bool vis[MAXN]; void init() { NE = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost; edge[NE].next = head[u]; head[u] = NE++; edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost; edge[NE].next = head[v]; head[v] = NE++; } bool SPFA(int s, int t, int n) { int i, u, v; queue <int> qu; memset(vis,false,sizeof(vis)); memset(pp,-1,sizeof(pp)); for(i = 0; i <= n; i++) dist[i] = INF; vis[s] = true; dist[s] = 0; qu.push(s); while(!qu.empty()) { u = qu.front(); qu.pop(); vis[u] = false; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].cap && dist[v] > dist[u] + edge[i].cost) { dist[v] = dist[u] + edge[i].cost; pp[v] = i; if(!vis[v]) { qu.push(v); vis[v] = true; } } } } if(dist[t] == INF) return false; return true; } int MCMF(int s, int t, int n) // minCostMaxFlow { int flow = 0; // 总流量 int i, minflow, mincost; mincost = 0; while(SPFA(s, t, n)) { minflow = INF + 1; for(i = pp[t]; i != -1; i = pp[edge[i].u]) if(edge[i].cap < minflow) minflow = edge[i].cap; flow += minflow; for(i = pp[t]; i != -1; i = pp[edge[i].u]) { edge[i].cap -= minflow; edge[i^1].cap += minflow; } mincost += dist[t] * minflow; } sumFlow = flow; // 题目需要流量,用于判断 return mincost; } int main() { int n,i,j,x; while(scanf("%d",&n)!=EOF) { init(); int S=1,T=n*n*2; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%d",&x); int u=(i-1)*n+j; addedge(u,u+n*n,1,-x); if(i<n) addedge(u+n*n,u+n,1,0); if(j<n) addedge(u+n*n,u+1,1,0); } } addedge(1,1+n*n,1,0); addedge(n*n,n*n*2,1,0); printf("%d\n",-MCMF(S,T,T)); } }