首页 > 技术文章 > P2046 [NOI2010]海拔

tcswuzb 2019-04-02 19:35 原文

题目链接

题意分析

首先一看就知道这是一道最小割

这里奉上最小割的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
#define ll long long
#define inf 0x7fffffff
#define N 500008
#define IL inline
#define M 5008611
#define D double
#define ull unsigned long long
#define R register
using namespace std;
template<typename T>IL void read(T &_)
{
    T __=0,___=1;char ____=getchar();
    while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}
    while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}
    _=___ ? __:-__;
}
/*-------------OI使我快乐-------------*/
int n,tot=1,S,T;
int to[M],nex[M],head[M],w[M];
int dep[M],cur[M];
ll ans;
queue<int> Q;
IL int id(int x,int y){return (x-1)*n+y;}
IL void add(int x,int y,int z)
{to[++tot]=y;nex[tot]=head[x];head[x]=tot;w[tot]=z;
swap(x,y);to[++tot]=y;nex[tot]=head[x];head[x]=tot;w[tot]=0;}
IL bool bfs()
{
    for(R int i=1;i<=T;++i) dep[i]=0;
    dep[S]=1;Q.push(S);
    for(;!Q.empty();)
    {
        int u=Q.front();Q.pop();
        for(R int i=head[u];i;i=nex[i])
        {
            int v=to[i];
            if(w[i]>0&&dep[v]==0)
            {
                dep[v]=dep[u]+1;Q.push(v);
            }
        }
    }
    return dep[T]!=0;
}
IL int dfs(int now,int res)
{
    if(now==T||!res) return res;
    for(R int &i=cur[now];i;i=nex[i])
    {
        int v=to[i];
        if(w[i]>0&&dep[v]==dep[now]+1)
        {
            
            int have=dfs(v,min(w[i],res));
            if(have>0)
            {
                w[i]-=have;w[i^1]+=have;return have;
            }
        }
    }
    return 0;
}
IL void Dinic()
{
    while(bfs())
    {
//		puts("now now now");
        for(R int i=1;i<=T;++i) cur[i]=head[i];
        int d=dfs(S,inf);
        while(d) ans+=1ll*d,d=dfs(S,inf);
    }
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
    read(n);++n;S=1;T=n*n;
    for(R int i=1;i<=n;++i)
     for(R int j=1,x;j<n;++j)
      read(x),add(id(i,j),id(i,j+1),x);
    for(R int i=1;i<n;++i)
     for(R int j=1,x;j<=n;++j)
      read(x),add(id(i,j),id(i+1,j),x);  
    for(R int i=1;i<=n;++i)
     for(R int j=1,x;j<n;++j)
      read(x),add(id(i,j+1),id(i,j),x);
    for(R int i=1;i<n;++i)
     for(R int j=1,x;j<=n;++j)
      read(x),add(id(i+1,j),id(i,j),x);   
    Dinic();
    printf("%lld\n",ans);   
//	fclose(stdin);
//	fclose(stdout);
    return 0;
}

但是直接平面图上跑最小割会\(TLE\)

思考一下 平面图上最小割模型就是一条分界线

我们思考可以转换为最短路问题

那么就是平面图转对偶图

一天左下角到右上角经过的就是分界线

例如说 画上箭头就是这样

然后我们跑最短路就可以了

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
#define ll long long
#define inf 0x7fffffff
#define N 500008
#define IL inline
#define M 5008611
#define D double
#define Pa pair<long long,int>
#define R register
using namespace std;
template<typename T>IL void read(T &_)
{
    T __=0,___=1;char ____=getchar();
    while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}
    while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}
    _=___ ? __:-__;
}
/*-------------OI使我快乐-------------*/
int n,tot,S,T;
int to[M],nex[M],head[M],w[M];
ll dis[M];bool vis[M];
priority_queue<Pa,vector<Pa >,greater<Pa > > Q;
IL int id(int x,int y){return (x-1)*n+y;}
IL void add(int x,int y,int z)
{to[++tot]=y;nex[tot]=head[x];head[x]=tot;w[tot]=z;}
IL void Dijkstra()
{
	memset(dis,0x3f,sizeof dis);Q.push(make_pair(dis[S]=0,S));
	for(;!Q.empty();)
	{
		int u=Q.top().second;Q.pop();
		if(vis[u]) continue;vis[u]=1;
		for(R int i=head[u];i;i=nex[i])
		{
			int v=to[i];
			if(dis[v]>dis[u]+w[i])
			Q.push(make_pair(dis[v]=dis[u]+w[i],v));
		}
	}
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	read(n);S=n*n+1;T=n*n+2;
	for(R int i=1;i<=n+1;++i)
	 for(R int j=1,x;j<=n;++j)
	 {
	 	read(x);
	 	if(i==1) add(id(i,j),T,x);
	 	else if(i==n+1) add(S,id(i-1,j),x);
	 	else add(id(i,j),id(i-1,j),x);
	 }
	for(R int i=1;i<=n;++i)
	 for(R int j=1,x;j<=n+1;++j)
	 {
	 	read(x);
	 	if(j==1) add(S,id(i,j),x);
	 	else if(j==n+1) add(id(i,j-1),T,x);
	 	else add(id(i,j-1),id(i,j),x);
	 } 
	for(R int i=1;i<=n+1;++i)
	 for(R int j=1,x;j<=n;++j)
	 {
	 	read(x);
	 	if(i==1) add(T,id(i,j),x);
	 	else if(i==n+1) add(id(i-1,j),S,x);
	 	else add(id(i-1,j),id(i,j),x);
	 } 
	for(R int i=1;i<=n;++i)
	 for(R int j=1,x;j<=n+1;++j)
	  {
	  	read(x);
	  	if(j==1) add(id(i,j),S,x);
	  	else if(j==n+1) add(T,id(i,j-1),x);
	  	else add(id(i,j),id(i,j-1),x);
 	  } 
 	Dijkstra();  
	printf("%lld\n",dis[T]);   
//	fclose(stdin);
//	fclose(stdout);
    return 0;
}

HEOI 2019 RP++

推荐阅读