Matrix(THUOI2011)

这个题出的很不错……伪装的很好!想,如果当年做过employee该多好~一个极度无语的网络流,伪装成高斯消元……这个思想值得借鉴。。

如果要做这个题,建议先做employee,体会连边方式,可以参考napkin。这几个题都有共同点,值得一做。

核心:把未知量看成边,把方程看成点,最大流的用处只是为了分配流量。。


照例code,99行的sap:

#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <math.h>

#define maxn 40050
#define maxm 40050
#define maxk 500500
#define maxv (maxn + maxm + 1)
#define maxe (maxv + maxk * 2)
#define oo 0x3F3F3F3F

typedef struct {int t, c, n;} etype;

int A[maxk];
int adm[maxv];
etype g[maxe << 1];
int vexsize, etop = 1, src, sink;
int dist[maxv];
int edge[maxv];
int gap[maxv], *queue = adm;
int pred[maxv];

void augment ()
{
  int i, e, width = oo;
  for (i = src, e = adm[i]; i != sink; i = g[e].t, e = adm[i])
    if (g[e].c < width)
      width = g[e].c;
  for (i = src, e = adm[i]; i != sink; i = g[e].t, e = adm[i])
    g[e].c -= width, g[e ^ 1].c += width;
}

void rev_bfs ()
{
  memset (dist, 0x3F, sizeof (dist)), dist[sink] = 0;
  int head = 0, tail = 0, i, e, dtmp, p;
  queue[++tail] = sink;
  for (; head != tail; )
    for (e = edge[i = queue[++head]], dtmp = dist[i] + 1; e; e = g[e].n)
      if (dist[p = g[e].t] > dtmp)
        gap[dist[queue[++tail] = p] = dtmp]++;
  vexsize = tail;
}

void isap ()
{
  rev_bfs ();
  memcpy (adm, edge, sizeof (adm));
  int i = src, e, dtmp, mindist;
  for (; dist[src] != vexsize; )
    {
      for (e = adm[i], dtmp = dist[i] - 1; e; e = g[e].n)
        if (g[e].c && dist[g[e].t] == dtmp)
          break;
      if (e)
        {
          adm[i] = e;
          pred[g[e].t] = i;
          i = g[e].t;
          if (i == sink)
            augment (), i = src;
        }
      else
        {
          if ((--gap[dist[i]]) == 0) return;
          e = adm[i] = edge[i];
          for (mindist = vexsize - 1; e; e = g[e].n)
            if (g[e].c && mindist > dist[g[e].t])
              mindist = dist[g[e].t];
          gap[dist[i] = mindist + 1]++;
          if (i != src) i = pred[i];
        }
    }
}

void adde (int s, int t, int c)
{
  g[++etop] = (etype){t, c, edge[s]}, edge[s] = etop;
  g[++etop] = (etype){s, 0, edge[t]}, edge[t] = etop;
}

int main ()
{
  freopen ("matrix.in" , "r", stdin);
  freopen ("matrix.out", "w", stdout);
  int n, m, k, i, x, y, u, v;
  scanf ("%d%d%d", &n, &m, &k), src = n + m + 1, sink = src + 1;
  for (i = 1; i <= k; ++i)
    scanf ("%d%d%d", &x, &y, &A[i]), adde (x, y + n, oo), adde (y + n, x, oo);
  for (i = 1; i <= n; ++i)
    scanf ("%d", &u), u ? adde (src, i, u) : 0;
  for (i = 1; i <= m; ++i)
    scanf ("%d", &v), v ? adde (i + n, sink, v) : 0;
  isap ();
  for (i = 1; i <= k; ++i)
    printf ("%0.8lf\n", 1.0 * (g[(i << 2) - 1].c - g[(i << 2) + 1].c) / A[i]);
  return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值