设为首页 加入收藏

TOP

HDU 4411 Arrest 费用流
2015-07-20 17:22:01 来源: 作者: 【 】 浏览:2
Tags:HDU 4411 Arrest 费用

题目链接:点击打开链接

题意:

给定n+1个点([0,n] )m条边的无向图。起点为0,k个人初始在起点,

去遍历图使得每个点至少被一人走过且遍历 i 点时 i-1 必须已经被遍历。

使得k人的路径和最小,最后k人要回到起点。

思路:

费用流,因为对于一个人来说,这个人遍历点的序列一定是一个递增序列(不需要连续)

所以建图时i的出点只需要连接i+? 的入点。

若建一个完全图则会因为spfa跑负环。。。


#include
  
   
#include
   
     #include
    
      #include
     
       #include
      
        using namespace std; #define ll int #define inf 1000000 #define Inf 0x3FFFFFFFFFFFFFFFLL #define N 250 #define M N*N*4 struct Edge { ll to, cap, cost, nex; Edge(){} Edge(ll to, ll cap, ll cost, ll next) :to(to), cap(cap), cost(cost), nex(next){} } edge[M << 1]; ll head[N], edgenum; ll D[N], A[N], P[N]; bool inq[N]; void add(ll from, ll to, ll cap, ll cost) { edge[edgenum] = Edge(to, cap, cost, head[from]); head[from] = edgenum++; edge[edgenum] = Edge(from, 0, -cost, head[to]); head[to] = edgenum++; } bool spfa(ll s, ll t, ll &flow, ll &cost) { for (ll i = 0; i <= t; i++) D[i] = inf; memset(inq, 0, sizeof inq); queue
       
        q; q.push(s); D[s] = 0; A[s] = inf; while (!q.empty()) { ll u = q.front(); q.pop(); inq[u] = 0; for (ll i = head[u]; ~i; i = edge[i].nex) { Edge &e = edge[i]; if (e.cap && D[e.to] > D[u] + e.cost) { D[e.to] = D[u] + e.cost; P[e.to] = i; A[e.to] = min(A[u], e.cap); if (!inq[e.to]) { inq[e.to] = 1; q.push(e.to); } } } } //若费用为inf则中止费用流 if (D[t] == inf) return false; cost += D[t] * A[t]; flow += A[t]; ll u = t; while (u != s) { edge[P[u]].cap -= A[t]; edge[P[u] ^ 1].cap += A[t]; u = edge[P[u] ^ 1].to; } return true; } ll Mincost(ll s, ll t){ ll flow = 0, cost = 0; while (spfa(s, t, flow, cost)); return cost; } void init(){ memset(head, -1, sizeof head); edgenum = 0; } const int MAXN = 105; int g[MAXN][MAXN]; int n, m, k; void floyd() { for (int k = 0; k <= n; k++) { for (int i = 0; i <= n; i++) { for (int j = 0; j <= n; j++) { if (g[i][j] > g[i][k] + g[k][j]) { g[i][j] = g[i][k] + g[k][j]; } } } } } int main(){ while (scanf("%d%d%d", &n, &m, &k) != EOF) { if (n == 0 && m == 0 && k == 0) break; for (int i = 0; i <= n; i++){ for (int j = 0; j <= n; j++) g[i][j] = 10000005; g[i][i] = 0; } for (int i = 0, u, v, w; i < m; i++) { scanf("%d%d%d", &u, &v, &w); g[u][v] = g[v][u] = min(w, g[u][v]); } floyd(); init(); int to = n * 2 + 3, from = n * 2 + 2; for (int i = 1; i <= n; i++){ add(0, i * 2, 1, g[0][i]); add(i * 2, i * 2 + 1, 1, -inf); add(i * 2 + 1, to, 1, g[i][0]); for (int j = i + 1; j <= n; j++) add(i * 2 + 1, j * 2, 1, g[i][j]); } add(from, 0, k, 0); add(0, to, k, 0); printf("%d\n", Mincost(from, to) + inf*n); } return 0; } 
       
      
     
    
   
  


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C++ boost库无锁队列多线程并行测.. 下一篇POJ 3169 Layout (差分约束系统 ..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·微服务 Spring Boot (2025-12-26 18:20:10)
·如何调整 Redis 内存 (2025-12-26 18:20:07)
·MySQL 数据类型:从 (2025-12-26 18:20:03)
·Linux Shell脚本教程 (2025-12-26 17:51:10)
·Qt教程,Qt5编程入门 (2025-12-26 17:51:07)