bzoj1001 【beijing2006】狼抓兔子

最小割問題

我用的裸的網絡流最大流最小割複雜度O((n^2)^3)沒想到就過了。。。速度和平面圖最小割的spfa算法差不多。。。

我的代碼:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n,m,size;
struct  node
{
	int len;
	int next;
	int to;
};
node bian[12000001];
int first[1000001];
bool exist[1000001];
int p[2000001];
int deep[1000001];


int read()
{
	int k=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
	while(c>='0'&&c<='9') {k=k*10+(c-'0'); c=getchar();}
	return k*f;
}
void inser(int a,int b,int c)
{
	size++;
	bian[size].to=b;
	bian[size].len=c;
	bian[size].next=first[a];
	first[a]=size;
	size++;
	bian[size].to=a;
	bian[size].len=0;
	bian[size].next=first[b];
	first[b]=size;
}

void bfs()
{
	int tail;
	int head;
	memset(deep,-1,sizeof(deep));
	tail=1;
	head=0;
	p[1]=1;
	exist[1]=1;
	deep[1]=1;
    int dd,i,u,k,j;
	while(head^tail)
	  {
	  	 head++;
	  	 u=p[head];
	  	 for(i=first[u];i;i=bian[i].next)
	  	   {
	  	   	 if(!bian[i].len) continue;
	  	   	 dd=bian[i].to;
	  	   	 if(!exist[dd])
	  	   	   {
			     exist[dd]=1;
				 deep[dd]=deep[u]+1;
				 if(exist[n*m]) return;
				 tail++;
				 p[tail]=dd;	   
		  	   }
		   }
	  }
}
int dfs(int x,int tot)
{
	int w=0;
	if(x==n*m) return tot;
	int dd,i,u;
	for(i=first[x];(i)&&tot>0;i=bian[i].next)
	  {
	  	if(!bian[i].len) continue;
	  	u=bian[i].to;
	  	if(deep[u]==deep[x]+1)
	  	  {
	  	    dd=dfs(u,min(tot,bian[i].len));
			w+=dd;  	
			tot-=dd;
	  	    bian[i].len-=dd;
			bian[i^1].len+=dd;  	
		  }
	  }
	if(!w) deep[x]=-1;
	return w;
}

int flow_max()
{
	int i,u;
	int ret=0;
	while(true)
	{
		memset(exist,0,sizeof(exist));
		bfs();
		if(!exist[n*m]) break;
	    while(true)
	    {
	      	u=dfs(1,1000000001);
	     	if(!u) break;
		    ret+=u;
		}
	}	
	return ret;
}




int main()
{
	freopen("lx.in","r",stdin);
	freopen("lx.out","w",stdout);
	int i,j,k;
    n=read();
    m=read();
    int s;
    size=1;
    for(i=1;i<=n;i++)
      {
      	for(j=1;j<m;j++)
      	  {
      	  	 s=read();
      	  	 inser(i*m+j-m,i*m+j+1-m,s);
      	  	 inser(i*m+j+1-m,i*m+j-m,s);
		  }		
	  }
	for(i=1;i<n;i++)
      {
      	for(j=1;j<=m;j++)
      	  {
      	  	 s=read();
      	  	 inser(i*m+j-m,i*m+j,s);
      	  	 inser(i*m+j,i*m+j-m,s);
		  }		
	  }
	for(i=1;i<n;i++)
      {
      	for(j=1;j<m;j++)
      	  {
      	  	 s=read();
      	  	 inser(i*m+j-m,i*m+j+1,s);
      	  	 inser(i*m+j+1,i*m+j-m,s);
		  }		
	  }
	int  ans=flow_max();
	cout<<ans;
	return 0;
}
正解:平面圖最小割(迪傑斯特拉+堆)


點化面

建立割邊(權值爲割掉的邊的權值)

跑0到13(即n*m+1)的最短路即可(用迪傑斯特拉+堆) 時間複雜度O((n^2)*log(n^2))

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章