p3422最小费最大流(未解决)

xiaoxiao2021-02-28  61

我真的好烦这个addEdge啊,每次看到这个就晕

没怎么看懂,不想看

题意:对于N*N的数组,给一个k,从(1,1)走到(N,N),走k次,走到每个点权值加上当前这个点的权值,之后这个点权值为0,求最大权值

对点进行拆分建图,一个点拆为两个点a和b,在a和b之间建一条花费为输入值容量为1的边,然后再建一条花费为0容量为k-1的边,对b点对于其右边和下边都建立一条容量为k花费为0的边,加入超级源点和汇点,花费为0容量为k,由此套模板就可以了

#include<iostream> #include<string.h> #include<stdio.h> #define min(a,b) ((a)<(b)?(a):(b)) using namespace std; const int nMax = 5005; const int eMax = 20050; struct {     int v, cap, cost, next, re; } edge[eMax]; int n, ans; int k, edgeHead[nMax]; int que[nMax], pre[nMax], dis[nMax]; bool vis[nMax]; void addEdge(int u, int v, int ca, int co) {     edge[k].v = v;     edge[k].cap = ca;     edge[k].cost = co;     edge[k].next = edgeHead[u];     edge[k].re = k + 1;     edgeHead[u] = k ++;     edge[k].v = u;     edge[k].cap = 0;     edge[k].cost = -co;     edge[k].next = edgeHead[v];     edge[k].re = k - 1;     edgeHead[v] = k ++; } bool spfa() {     int i, head = 0, tail = 1;     //一开始用堆栈,用了980多MS,囧...     for(i = 0; i <= n; i ++)     {         dis[i] = -1;         vis[i] = false;     }     dis[0] = 0;     que[0] = 0;     vis[0] = true;     while(head != tail)     {         int u = que[head];         for(i = edgeHead[u]; i != 0; i = edge[i].next)         {             int v = edge[i].v;             if(edge[i].cap && dis[v] < dis[u] + edge[i].cost)             {                 dis[v] = dis[u] + edge[i].cost;                 pre[v] = i;                 if(!vis[v])                 {                     vis[v] = true;                     que[tail ++] = v;                     if(tail == nMax) tail = 0;                 }             }         }         vis[u] = false;         head ++;         if(head == nMax) head = 0;     }     if(dis[n] <= 0) return false;     return true; } void end() {     int u, p;     for(u = n; u != 0; u = edge[edge[p].re].v)     {         p= pre[u];         edge[p].cap -= 1;         edge[edge[p].re].cap += 1;         ans += edge[p].cost;     } } int main() {     int N, K, map[52][52], i, j;     scanf("%d%d", &N, &K);     for(i = 1; i <= N; i ++)         for(j = 1; j <= N; j ++)             scanf("%d", &map[i][j]);     for(k = i = 1; i <= N; i ++)         for(j = 1; j <= N; j ++)         {             int a = (i-1)*N + j;             int b = a + N*N;             addEdge(a, b, 1, map[i][j]);             //拆点,连2条边。             addEdge(a, b, K, 0);             if(i < N) addEdge(b, a+N, K, 0);             // 向下的点连边             if(j < N) addEdge(b, a+1, K, 0);             // 向右的点连边         }     n = 2*N*N + 1;     addEdge(0, 1, K, 0);     // 连源点的边。     addEdge(2*N*N, n, K, 0);     // 连汇点的边。     ans = 0;     while(spfa())          end();     printf("%d\n", ans);     return 0; }

转载请注明原文地址: https://www.6miu.com/read-61295.html

最新回复(0)