bzoj-1001 狼抓兔子

141 篇文章 0 订阅
44 篇文章 0 订阅

题意:

给出一个n*m的下面这样的图,求此图的最小割;


n,m<=1000;


题解:

这题说好的简单题结果怎么如此丧病;

最简单的想法就是求最小割就是求最小割嘛;

然后一发Dinic搞定;

然而似乎现在不能这么A了= =

所以这个图有一些特殊的性质,这是一个平面图;

而对于一个平面图的割来说,一定是一条曲线割开了一些线段;

那么如果将这些平面视为点,边视为连接两个平面的边;

那么从左下的平面连到右上区域的一条最短路就是此图的最小割了;

内存好大啊。。时间复杂度大概是O(k*n*m);

思路简单细节有点恶心;

1.加边记得双向;

2.n==1或m==1特判;

3.读入各种n,m弄反。。


代码:


#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 2500000
using namespace std;
queue<int>q;
int to[N<<2],next[N<<2],val[N<<2],head[N],tot;
int num[2100][1100],s,t;
int dis[N];
bool inq[N];
void add(int x,int y,int v)
{
	to[++tot]=y,next[tot]=head[x],val[tot]=v,head[x]=tot;
}
int spfa()
{
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0,inq[s]=1;
	q.push(s);
	int x,y,i;
	while(!q.empty())
	{
		x=q.front(),q.pop();
		inq[x]=0;
		for(i=head[x];i;i=next[i])
		{
			if(dis[y=to[i]]>dis[x]+val[i])
			{
				dis[y]=dis[x]+val[i];
				if(!inq[y])
					inq[y]=1,q.push(y);
			}
		}
	}
	return dis[t];
}
void SPJ(int n)
{
	int ret=0x3f3f3f3f,x;
	for(int i=1;i<n;i++)
	{
		scanf("%d",&x);
		ret=min(ret,x);
	}
	printf("%d\n",ret);
	exit(0);
}
int main()
{
	int n,m,i,j,k,x,y,v;
	scanf("%d%d",&n,&m);
	if(n==1||m==1)
		SPJ(n==1?m:n);
	for(i=1,k=0;i<=n+n-2;i++)
		for(j=1;j<m;j++)
			num[i][j]=++k;
	s=++k,t=++k;
	for(i=1;i<m;i++)
	{
		scanf("%d",&v);
		add(num[1][i],t,v);
	}
	for(i=2;i<n;i++)
	{
		for(j=1;j<m;j++)
		{
			scanf("%d",&v);
			add(num[i+i-1][j],num[i+i-2][j],v);
			add(num[i+i-2][j],num[i+i-1][j],v);
		}
	}
	for(i=1;i<m;i++)
	{
		scanf("%d",&v);
		add(s,num[n+n-2][i],v);
	}
	for(i=1;i<n;i++)
	{
		scanf("%d",&v);
		add(s,num[i+i][1],v);
		for(j=1;j<m-1;j++)
		{
			scanf("%d",&v);
			add(num[i+i-1][j],num[i+i][j+1],v);
			add(num[i+i][j+1],num[i+i-1][j],v);
		}
		scanf("%d",&v);
		add(num[i+i-1][m-1],t,v);
	}
	for(i=1;i<n;i++)
	{
		for(j=1;j<m;j++)
		{
			scanf("%d",&v);
			add(num[i+i][j],num[i+i-1][j],v);
			add(num[i+i-1][j],num[i+i][j],v);
		}
	}
	printf("%d\n",spfa());
	return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值