题意:动物园,需要拦截动物,这里有呈现矩形状的路,每条路需要一定人数才能堵住路,求阻止动物从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;
}