zoukankan      html  css  js  c++  java
  • 【XSY2849】陈姚班 平面图网络流 最短路 DP

    题目描述

      有一个(n)(m)列的网格图。

      (S)到第一行的每一个点都有一条单向边,容量为(infty)

      最后一行的每个点到(T)都有一条单向边,容量为(infty)

      同一行中相邻的两个节点之间有一条无向边,((x,y))((x,y+1))之间的无向边的容量为(a_{x,y})

      同一列中相邻的两个节点之间有两条有向边,((x,y))((x+1,y))这条有向边的容量为(b_{x,y})((x+1,y))((x,y))这条有向边容量为(infty)

      求(S)(T)的最大流。

      特别的,(forall i,a_{1,i}=a_{n,i}=0)

      (n imes mleq 25000000)

    题解

      显然这是一个网络流。

      直接跑网络流会TLE。

      观察到这个图是一个平面图,可以把平面图网络流转化为对偶图最短路。

      怎么转化呢?

      首先你要会无向边的平面图网络流(可以百度/google)。

      有向边的连边方法和无向边的类似。

      对于一条有向边(x ightarrow y),容量为(z)的有向边(网络流最后都是在有向边上面跑的),从(x ightarrow y)这条有向边的左边对应的这个区域连一条边到右边的这个区域,权值为(z)

      最后跑一次最短路就行了。

      这道题中从下往上的边的容量为(infty),所以对偶图中从左往右的边的权值为(infty),也就是说最短路的每一步只会向上/下/左走,这就可以DP了。

      设(f_{i,j})为走到((x,y))右下方那个区域的最短路

    [f_{i,j}=min(f_{i-1,j}+a_{i,j},f_{i+1,j}+a_{i+1,j},f_{i,j+1}+b_{i+1,j}) ]

      时间复杂度:(O(nm))

      我的代码中把左右反过来了

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<cmath>
    #include<functional>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> pll;
    void sort(int &a,int &b)
    {
    	if(a>b)
    		swap(a,b);
    }
    void open(const char *s)
    {
    #ifndef ONLINE_JUDGE
    	char str[100];
    	sprintf(str,"%s.in",s);
    	freopen(str,"r",stdin);
    	sprintf(str,"%s.out",s);
    	freopen(str,"w",stdout);
    #endif
    }
    int rd()
    {
    	int s=0,c;
    	while((c=getchar())<'0'||c>'9');
    	do
    	{
    		s=s*10+c-'0';
    	}
    	while((c=getchar())>='0'&&c<='9');
    	return s;
    }
    void put(int x)
    {
    	if(!x)
    	{
    		putchar('0');
    		return;
    	}
    	static int c[20];
    	int t=0;
    	while(x)
    	{
    		c[++t]=x%10;
    		x/=10;
    	}
    	while(t)
    		putchar(c[t--]+'0');
    }
    int upmin(int &a,int b)
    {
    	if(b<a)
    	{
    		a=b;
    		return 1;
    	}
    	return 0;
    }
    int upmax(int &a,int b)
    {
    	if(b>a)
    	{
    		a=b;
    		return 1;
    	}
    	return 0;
    }
    int *a;
    int n,m;
    int A,B,Q;
    int down(int x,int y)
    {
    	return a[(x-1)*m+y];
    }
    int right(int x,int y)
    {
    	return a[(n-1)*m+(x-2)*(m-1)+y];
    }
    ll *f;
    int main()
    {
    	open("c");
    	scanf("%d%d",&n,&m);
    	a=new int[(n-1)*m+(n-2)*(m-1)+1];
    	scanf("%d%d%d%d",&A,&B,&Q,&a[0]);
    	for(int i=1;i<=(n-1)*m+(n-2)*(m-1);i++)
    		a[i]=((ll)a[i-1]*A+B)%Q;
    	f=new ll[n];
    	for(int i=1;i<n;i++)
    		f[i]=0;
    	for(int i=1;i<m;i++)
    	{
    		for(int j=1;j<n;j++)
    			f[j]+=down(j,i);
    		for(int j=2;j<n;j++)
    			f[j]=min(f[j],f[j-1]+right(j,i));
    		for(int j=n-2;j>=1;j--)
    			f[j]=min(f[j],f[j+1]+right(j+1,i));
    	}
    	ll ans=0x7fffffffffffffffll;
    	for(int i=1;i<n;i++)
    		ans=min(ans,f[i]+down(i,m));
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    第 2 章 OpenStack 架构
    第 2 章 OpenStack 架构
    第 1 章 虚拟化
    第 1 章 虚拟化
    第 1 章 虚拟化
    第 1 章 虚拟化
    第 1 章 虚拟化
    第 1 章 虚拟化
    第 1 章 虚拟化
    第 1 章 虚拟化
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8919303.html
Copyright © 2011-2022 走看看