UVALIVE 3661 Animal Run <最大-最小原理之一 最大流-最小割原理>

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1662

题意:动物园,需要拦截动物,这里有呈现矩形状的路,每条路需要一定人数才能堵住路,求阻止动物从start到end最小需要多少人?

分析:最大流-最小割定理


                                  利用最短路求最大流

•[定理2.1]
可以在O(nlog2n)的时间内求出s-t平面图上的最大流。
•[定义3.1]
最大—最小定理是一类描述同一个对象上的一个最大化问题的解和一个最小化问题的解之间的关系的定理。

SPFA法会 Time limit exceeded
这里用下面方法就不会超时了
priority_queue法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <bits/stdc++.h>

using namespace std;
const int N = 1111 * 1111 * 3;
#define INF 0x3f3f3f3f
#define rep(i,p) for(int i=1;i<=p;i++)
int n,m;
struct Edge
{
    int to,next,dist;
}e[N<<2];
int dis[N],sink,source,tot,cas;
bool vis[N];
int head[N];
void ADD(int from,int to,int dist)
{
    e[tot].to = to;
    e[tot].dist = dist;
    e[tot].next  = head[from];
    head[from] = tot++;
}
void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
    source = 2*(n-1)*(m-1)+2;
    sink = source - 1;
    int u,v,d;
    rep(i,n)
      rep(j,m-1)
         {
             scanf("%d",&d);
             if(i==1)
             {
                 v = 2*j;
                 ADD(sink,v,d);
                 ADD(v,sink,d);
             }
             else if(i==n)
             {
                  u = 2 * (m - 1) * (i - 2) + 2 * (j - 1) + 1;

                 ADD(source,u,d);ADD(u,source,d);
             }
             else
             {
                  u = 2 * (m - 1) * (i - 2) + 2 * (j - 1) + 1;
                 v = u + 2 * (m - 1) + 1;
                 ADD(u,v,d);
                 ADD(v,u,d);
             }
         }
    rep(i,n-1)
       rep(j,m)
       {
           scanf("%d",&d);
           if(j==1)
           {
               u = 2 * (m - 1) * (i - 1) + 1;
               ADD(u,source,d);
               ADD(source,u,d);
           }
           else if(j==m)
           {
               v = 2 * (m - 1) * i;

               ADD(v,sink,d); ADD(sink,v,d);
           }
           else
           {
               u = 2 * (m - 1) * (i - 1) + 2 * (j - 1);
                v = u + 1;
                ADD(u, v, d);
                ADD(v, u, d);
           }
       }
   rep(i,n-1)
     rep(j,m-1)
       {
           scanf("%d",&d);
           u = 2 *(i-1)*(m-1)+j*2-1;
           v = u+1;
           ADD(u,v,d);
           ADD(v,u,d);
       }
}

struct Node
{
    int id,val;
    Node(int id, int val): id(id), val(val) {}
    bool operator < (const Node& nn) const
    {
        return val > nn.val;
    }
};
void solve()
{
    memset(vis,false,sizeof(vis));
    rep(i,sink) dis[i] = INF;
   priority_queue<Node> que;
    dis[source] = 0;
    que.push(Node(source,0));
    int u,v,i;
    while(!que.empty())
    {
        Node cur = que.top();
        que.pop();
        u = cur.id;
       // printf("que  start.\n");
        if(vis[u])
            continue;
        vis[u] = true;
        for(i = head[u];i!=-1;i = e[i].next)
        {
           // printf("i = %d v = %d\n",i,e[i].to);
               v = e[i].to;
              if(dis[v] > dis[u]+e[i].dist)
                {
                    dis[v] = dis[u] + e[i].dist;
                    que.push(Node(v,dis[v]));
                }


        }
    }
}
void print()
{
    printf("Case %d: Minimum = %d\n", ++cas, dis[sink]);
}
int main()
{
    cas = 0;
    while(scanf("%d %d",&n,&m)!=EOF&&(n+m))
    {
        init();
        solve();
        print();
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值