pku 1087 A Plug for UNIX 网络流 解题报告

pku 1087 A Plug for UNIX 网络流 解题报告

十分郁闷的一题,与其说是练习算法与编程,还不如说练习你的英语.算法一般般,很多人都能想到.不是最大流就是利用二分图.可我在这过程中,总是建错图.原因在于没有理解好题意啊.sample:

4

A

B

C

D

5

laptop B

phone C

pager B

clock B

comb X

3

B X

X A

X D

n=4,其中ABCD指的是插座而且是可以直接通电的,m=5,左边的是电器,右边的则是电器相对应的插座,同时不一定是直接通电的,X就是这样.但剩下的k=3,则是插座两两之间的联系.BX联系,XA联系,XD联系,那么laptop则可以直接与B连接通电,或者通过XAD连接通电.其他的以此类推.

AC代码:(采用最大流的算法)

 

#include <stdio.h>

#include <string.h>

#define inf 21100000

#define MAXN 505

 

int n, m, k, total, source, sink;

int mat[MAXN][MAXN], flow[MAXN][MAXN];

char device[MAXN][30];

 

int get_id(char b[])

{

   int i;

   for (i = 1; i <= total; i++)

   {

      if (strcmp(device[i], b) == 0)

      {

        return i + m - 1;

      }

   }

   total++;

   strcpy(device[i], b);

   return i + m - 1;

}

 

void init()

{

   int i, ii, j, jj;

   char a[MAXN][30], b[30], c[30];

   source = 0; total = 1;

   memset(mat, 0, sizeof(mat));

   scanf("%d", &n);

   for (i = 1; i <= n; i++)

   {

      scanf("%s", a[i]);

   }

   scanf("%d", &m);

   for (i = 1; i <= m; i++)

   {

      mat[0][i] = 1;

      scanf("%s %s", b, c);

      j = get_id(c);

      mat[i][j] = 1;

   }

   scanf("%d", &k);

   for (i = 1; i <= k; i++)

   {

      scanf("%s %s", b, c);

      j = get_id(b);

      jj = get_id(c);

      mat[j][jj] = inf;

   }

   for (i = 1; i <= n; i++)

   {

      j = get_id(a[i]);

   }

   ii = m + total;

   for (i = 1; i <= n; i++)

   {

      j = get_id(a[i]);

      mat[j][ii] = 1;

   }

   sink = ii;

   n = ii + 1;

}

 

//返回最大流量,flow返回每条边的流量

//传入网络节点数n,容量mat,源点source,汇点sink

int max_flow()

{

 

    int pre[MAXN], que[MAXN], d[MAXN], p, q, t, i, j;

  

   if (source == sink)

   {

      return inf;

   }

    for (i = 0; i < n; i++)

   {

      for (j = 0; j < n; j++)

        {

        flow[i][j] = 0;

      }

   }

    while (1)

   {

        for (i = 0; i < n; i++)

      {

        pre[i] = 0;

      }

      t = source;

        pre[t] = 1;

      d[t] = inf;

        for (p = q = 0; p <= q && !pre[sink]; )

      {

        for (i = 0; i < n; i++)

        {

           if (!pre[i] && (j = mat[t][i] - flow[t][i]))

           {

              pre[que[q++] = i] = t + 1;

              d[i] = d[t] < j ? d[t] : j;

           }

                else if (!pre[i] && (j = flow[i][t]))

           {

              pre[que[q++] = i] = - t - 1;

              d[i] = d[t] < j ? d[t] : j;

           }

        }

        t = que[p++];

      }

        if (!pre[sink])

      {

        break;

      }

        for (i = sink; i != source;)

        {

        if (pre[i] > 0)

        {

           flow[pre[i] - 1][i] += d[sink];

           i = pre[i] - 1;

        }

            else

        {

           flow[i][-pre[i] - 1] -= d[sink];

           i = -pre[i] - 1;

        }

      }

    }

    for (j = i = 0; i < n; j += flow[source][i++])

   {

      ;

   }

    return j;

}

 

int main()

{

   init();

   int ans, temp = max_flow();

   if (temp > m)

   {

      ans = m;

   }

   else

   {

      ans = m - temp;

   }

   printf("%d/n", ans);

   return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值