zoukankan      html  css  js  c++  java
  • BZOJ.2007.[NOI2010]海拔(最小割 对偶图最短路)

    题目链接

    想一下能猜出,最优解中海拔只有0和1,且海拔相同的点都在且只在1个连通块中。
    这就是个平面图最小割。也可以转必须转对偶图最短路,不然只能T到90分了。。边的方向看着定就行。
    不能忽略回去的边,因为最小割的形状可能很奇怪。

    //16232kb	456ms
    //平面图点数就是(n-1)^2了。但是边数不是4(n-1)^2,是4n(n-1)!。。
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    #define mp std::make_pair
    #define pr std::pair<LL,int>
    #define ID(x,y) ((x-1)*nn+y)
    typedef long long LL;
    const int N=500*500+5,M=4*500*501+5;
    
    int n,nn,Enum,H[N],nxt[M],to[M],len[M];
    bool vis[N];
    LL dis[N];
    std::priority_queue<pr> q;
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    #define AddEdge(u,v) to[++Enum]=v,nxt[Enum]=H[u],H[u]=Enum,len[Enum]=read()
    LL Dijkstra(int S,int T)
    {
    	memset(dis,0x3f,sizeof dis);
    	dis[S]=0, q.push(mp(0,S));
    	while(!q.empty())
    	{
    		int x=q.top().second; q.pop();
    		if(vis[x]) continue;
    		vis[x]=1;
    		for(int i=H[x]; i; i=nxt[i])
    			if(dis[to[i]]>dis[x]+len[i])
    				q.push(mp(-(dis[to[i]]=dis[x]+len[i]),to[i]));
    	}
    	return dis[T];
    }
    
    int main()
    {
    	n=read()+1, nn=n-1; int S=0, T=nn*nn+1;
    
    	for(int j=1; j<n; ++j) AddEdge(S,ID(1,j));//i==1
    	for(int i=2; i<n; ++i)
    		for(int j=1; j<n; ++j) AddEdge(ID(i-1,j),ID(i,j));
    	for(int j=1; j<n; ++j) AddEdge(ID(nn,j),T);//i==n
    
    	for(int i=1; i<n; ++i)
    	{
    		AddEdge(ID(i,1),T);//j==1
    		for(int j=2; j<n; ++j) AddEdge(ID(i,j),ID(i,j-1));
    		AddEdge(S,ID(i,nn));//j==n
    	}
    
    	for(int j=1; j<n; ++j) AddEdge(ID(1,j),S);
    	for(int i=2; i<n; ++i)
    		for(int j=1; j<n; ++j) AddEdge(ID(i,j),ID(i-1,j));
    	for(int j=1; j<n; ++j) AddEdge(T,ID(nn,j));
    
    	for(int i=1; i<n; ++i)
    	{
    		AddEdge(T,ID(i,1));
    		for(int j=2; j<n; ++j) AddEdge(ID(i,j-1),ID(i,j));
    		AddEdge(ID(i,nn),S);
    	}
    
    	printf("%lld
    ",Dijkstra(S,T));
    
    	return 0;
    }
    

    90分(洛谷)网络流:

    /*
    还是建反向边吧,虽然会有一条反向边,但是很难对应上去。。
    注意n要加1,即点数是501*501=251001而不是250000。。够坑(也就坑我这种卡的了)。
    */
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define MAXIN 300000
    //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    #define ID(x,y) ((x-1)*n+y)
    const int N=501*501+5/*>250005!*/,M=N<<3,INF=0x3f3f3f3f;
    
    int n,src,des,Enum,H[N],cur[N],nxt[M],fr[M],to[M],cap[M],lev[N],pre[N],num[N];
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline void AddEdge(int w,int u,int v)
    {
    	to[++Enum]=v, fr[Enum]=u, nxt[Enum]=H[u], H[u]=Enum, cap[Enum]=w;
    	to[++Enum]=u, fr[Enum]=v, nxt[Enum]=H[v], H[v]=Enum, cap[Enum]=0;
    }
    bool BFS()
    {
    	static int q[N];
    	for(int i=src; i<des; ++i) lev[i]=des+1;
    	int h=0,t=1; q[0]=des, lev[des]=0;
    	while(h<t)
    	{
    		int x=q[h++];
    		for(int i=H[x]; i; i=nxt[i])
    			if(lev[to[i]]==des+1 && cap[i^1])
    				lev[to[i]]=lev[x]+1, q[t++]=to[i];
    	}
    	return lev[src]<=des;
    }
    int Augment()
    {
    	int mn=INF;
    	for(int i=des; i!=src; i=fr[pre[i]])
    		mn=std::min(mn,cap[pre[i]]);
    	for(int i=des; i!=src; i=fr[pre[i]])
    		cap[pre[i]]-=mn, cap[pre[i]^1]+=mn;
    	return mn;
    }
    long long ISAP()
    {
    	if(!BFS()) return 0;
    	for(int i=src; i<=des; ++i) ++num[lev[i]],cur[i]=H[i];
    	int x=src; long long res=0;
    	while(lev[src]<=des)
    	{
    		if(x==des) x=src,res+=Augment();
    		bool can=0;
    		for(int i=cur[x]; i; i=nxt[i])
    			if(lev[to[i]]==lev[x]-1 && cap[i])
    			{
    				can=1, cur[x]=i, pre[x=to[i]]=i;
    				break;
    			}
    		if(!can)
    		{
    			int mn=des;
    			for(int i=H[x]; i; i=nxt[i])
    				if(cap[i]) mn=std::min(mn,lev[to[i]]);
    			if(!--num[lev[x]]) break;
    			++num[lev[x]=mn+1], cur[x]=H[x];
    			if(x!=src) x=fr[pre[x]];
    		}
    	}
    	return res;
    }
    
    int main()
    {
    	n=read()+1, Enum=1, src=1, des=n*n;
    	for(int i=1; i<=n; ++i)
    		for(int j=1; j<n; ++j) AddEdge(read(),ID(i,j),ID(i,j+1));
    	for(int i=1; i<n; ++i)
    		for(int j=1; j<=n; ++j) AddEdge(read(),ID(i,j),ID(i+1,j));
    	for(int i=1; i<=n; ++i)
    		for(int j=1; j<n; ++j) AddEdge(read(),ID(i,j+1),ID(i,j));
    	for(int i=1; i<n; ++i)
    		for(int j=1; j<=n; ++j) AddEdge(read(),ID(i+1,j),ID(i,j));
    	printf("%lld
    ",ISAP());
    
    	return 0;
    }
    
  • 相关阅读:
    git问题记录
    @Slf4j注解
    idea修改maven项目名
    spring的定时任务schedule
    @RequestParam详解
    统一全局异常处理将出错的栈信息打印到日志中
    python交互环境中导入文件中自定义的函数报错
    关于服务器的小技巧
    Python学习
    前后端分离时,获取不到session
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9534702.html
Copyright © 2011-2022 走看看