重要秘密

Description

圆蛋节到来,学校又开始短暂的放假了,大部分人们都很欢乐。虽然不知道OIER们心情是否很愉快,可以确定的是ACMER们确实放假了, 所以他们脸上充满了笑容,终于有时间集体开黑刷水题了,然后集体开黑放羊去。 

与此同时,NAOCAN_HELLIS发现了一个很恼火的现象,当大家沉醉于集体开黑的时候,学校的渣渣网络变得异常的卡。然后,NAOCAN_HELLIS发现了一个更恼火的问题,在此等危急存亡的时刻,有一个重要文件需要通过网络传送给某PLMM。 
网络可以简单地n*m的节点组成,例如下面2*4的网络, 

 


Rij 和Dij 为某网络中的传输速度,R和D的方向是固定的,R向右,D向下。而且网络中的边不会有缺,如上图所示。整个网络可以同时工作,边的传输速度决定单位时间内通过该边的流量。并且当一个网络的以最大传输速度工作时,从S到end的单位流量为W,那么不可能还有流量可以从S传输到end。 
现在NAOCAN_HELLIS现在想知道网络的最大传输速度是多少。

Input

多组测试数据。每组测试数据格式为: 
第一行2个整数n,m。其中0<n,m<=100。 
接下来是n *(m-1)的矩阵表示Rij 
其中0 < Rij <=10000 
接下来是(n -1)*m的矩阵表示Dij 
其中0 < Dij <=10000

Output

每组测试数据输出包含一行1个整数,即网络最大传输速度。

Sample Input

2 2
4 
1 
2 4 

5 5
4 15 15 10 
4 7 16 7 
5 5 15 26 
15 22 6 2 
6 6 11 11 

7 3 15 2 5 
14 23 15 20 11 
6 12 11 8 5 
9 13 10 13 12 

Sample Output

5
11

Hint

测试数据不超过200组。注意优化。


【分析】

        很明显是平面图网络流,我们采用重新建图后求最短路的方法。

如图:

我们将原图的起点终点用一个虚拟的线连起来。在新图中,每个点对应原图的一个区域,我们定义Sta,End,即起点终点如图所示。然后对节点连边,红色边的权值为所割边的流量,蓝色边的权值为0。


【代码】

/**************************
    ID:Ciocio
	LANG:C++
	DATE:2013-12-04
	TASK:Secret
**************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <utility>
#include <functional>
#include <vector>
#include <map>

using namespace std;

#define MAXM 60000
#define loc(x,y) ((x-1)*(M-1)+y)
#define pii pair<int,int>
#define m_p make_pair

int N,M,Sta,End;
int dis[MAXM];
bool vis[MAXM];
struct Edge{
	int v,d;
	Edge *Next;
}E[MAXM];

void _read(int &x)
{
	char tt=getchar();
	while(tt<'0'||'9'<tt) tt=getchar();
	for(x=0;'0'<=tt&&tt<='9';x=(x<<3)+(x<<1)+tt-'0',tt=getchar());
}

Edge *tot;
Edge *Last[MAXM];
inline void _addedge(int u,int v,int d)
{
	Edge *p=++tot;
	p->v=v;
	p->d=d;
	p->Next=Last[u];
	Last[u]=p;
}

void _init()
{
	int Cost;
	for(int i=1;i<=N;i++)       //重建图
		for(int j=1;j<M;j++)
		{
			_read(Cost);
			if(i==1)
				_addedge(loc(1,j),End,Cost);
			else if(i==N)
				_addedge(Sta,loc(N-1,j),Cost);
			else
			{
				_addedge(loc(i-1,j),loc(i,j),0);
				_addedge(loc(i,j),loc(i-1,j),Cost);
			}
		}
	for(int i=1;i<N;i++)
		for(int j=1;j<=M;j++)
		{
			_read(Cost);
			if(j==1)
				_addedge(Sta,loc(i,1),Cost);
			else if(j==M)
				_addedge(loc(i,M-1),End,Cost);
			else 
			{
				_addedge(loc(i,j),loc(i,j-1),0);
				_addedge(loc(i,j-1),loc(i,j),Cost);
			}
		}
}

priority_queue <pii,vector<pii>,greater<pii> > PQ;
void _solve()
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	while(!PQ.empty()) PQ.pop();
	dis[Sta]=0;
	PQ.push(m_p(dis[Sta],Sta));
	while(!PQ.empty())
	{
		int u;
		do u=PQ.top().second,PQ.pop();
		while(vis[u]);
		if(u==End) break;        //重要优化
		vis[u]=true;
		for(Edge *p=Last[u];p;p=p->Next)
		{
			int v=p->v,d=p->d;
			if((!vis[v])&&(dis[v]>dis[u]+d))
			{
				dis[v]=dis[u]+d;
				PQ.push(m_p(dis[v],v));
			}
		}
	}
	cout<<dis[End]<<endl;
}

int main()
{
	while(scanf("%d%d",&N,&M)!=EOF)
	{
		Sta=0;End=(N-1)*(M-1)+1;
		tot=&E[0];
		for(int i=Sta;i<=End;i++) Last[i]=NULL;      //注意初始化
	    _init();
	    _solve();
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值