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;
    }
    
  • 相关阅读:
    SharePoint 2013 APP 开发示例 (六)服务端跨域访问 Web Service (REST API)
    麦咖啡导致电脑不能上网
    SharePoint 2013 Central Admin 不能打开
    SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API)
    SharePoint 2013 APP 开发示例 系列
    synthesize(合成) keyword in IOS
    Git Cmd
    简单的正则匹配
    Dropbox
    SQL Server Replication
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9534702.html
Copyright © 2011-2022 走看看