• P4009 汽车加油行驶问题


    (color{#0066ff}{题目描述})

    给定一个 (N imes N) 的方形网格,设其左上角为起点o,坐标((1,1))(X) 轴向右为正, (Y) 轴向下为正,每个方格边长为 (1) ,如图所示。

    一辆汽车从起点出发驶向右下角终点,其坐标为 ((N,N))

    在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:

    汽车只能沿网格边行驶,装满油后能行驶 (K) 条网格边。出发时汽车已装满油,在起点与终点处不设油库。

    汽车经过一条网格边时,若其 (X) 坐标或 (Y) 坐标减小,则应付费用 (B) ,否则免付费用。

    汽车在行驶过程中遇油库则应加满油并付加油费用 (A)

    在需要时可在网格点处增设油库,并付增设油库费用 (C)(不含加油费用(A) )。

    (N,K,A,B,C) 均为正整数, 且满足约束: (2leq Nleq 100,2 leq K leq 10)

    设计一个算法,求出汽车从起点出发到达终点所付的最小费用。

    (color{#0066ff}{输入格式})

    文件的第一行是 (N,K,A,B,C) 的值。

    第二行起是一个(N imes N)(0-1) 方阵,每行 (N) 个值,至 (N+1) 行结束。

    方阵的第 (i) 行第 (j) 列处的值为 (1) 表示在网格交叉点 ((i,j)) 处设置了一个油库,为 (0) 时表示未设油库。各行相邻两个数以空格分隔。

    (color{#0066ff}{输出格式})

    程序运行结束时,输出最小费用。

    (color{#0066ff}{输入样例})

    9 3 2 3 6
    0 0 0 0 1 0 0 0 0
    0 0 0 1 0 1 1 0 0
    1 0 1 0 0 0 0 1 0
    0 0 0 0 0 1 0 0 1
    1 0 0 1 0 0 1 0 0
    0 1 0 0 0 0 0 1 0
    0 0 0 0 1 0 0 0 1
    1 0 0 1 0 0 0 1 0
    0 1 0 0 0 0 0 0 0
    

    (color{#0066ff}{输出样例})

    12
    

    (color{#0066ff}{数据范围与提示})

    (2leq nleq 100,2leq kleq 10)

    (color{#0066ff}{题解})

    可以发现,k只有10,所以可以暴力O(nmk)建立分层图

    分层图,每一层油量相同(可以理解为每个点拆成k个点,k个油)

    超级源连(1,1),注意,(n,n),的每一层都要连超级汇(考虑所有情况)

    相邻两个点,每一层都要连边,还要考虑消耗油和补充油的跨层连边,肯定MLE了qwq

    所以考虑全连在第一层上(第一层是满油的点)

    把当前点所有油的情况全连在满油上,代表无论什么情况,都可以花费一些钱(要么自建,要么用现成的加油站)把油加满

    这样,对于每个点,枚举4个方向,从4个方向对应的每种情况向当前点连边

    由题意易得,所有的容量都是1,跑一遍费用流就行了

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    #define _ 0
    #define LL long long
    inline LL in()
    {
    	LL x=0,f=1; char ch;
    	while(!isdigit(ch=getchar()))(ch=='-')&&(f=-f);
    	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    	return x*f;
    }
    int n,k,a,b,c,s,t,max;
    const int mod=1005050;
    struct node
    {
    	int to,dis,can;
    	node *nxt,*rev;
    	node(int to=0,int dis=0,int can=0,node *nxt=NULL):to(to),dis(dis),can(can),nxt(nxt){}
    	void *operator new (size_t)
    	{
    		static node *S=NULL,*T=NULL;
    		return (S==T&&(T=(S=new node[1024])+1024)),S++;
    	}
    };
    const int inf=0x7fffffff;
    typedef node* nod;
    bool vis[mod];
    nod head[mod],road[mod];
    int dis[mod],change[mod];
    int rx[]={1,0,-1,0};
    int ry[]={0,1,0,-1};
    std::queue<int> q;
    inline void add(int from,int to,int dis,int can)
    {	
    	nod o=new node(to,dis,can,head[from]);
    	head[from]=o;
    }
    inline void link(int from,int to,int dis,int can)
    {
    	add(from,to,dis,can);
    	add(to,from,-dis,0);
    	head[from]->rev=head[to];
    	head[to]->rev=head[from];
    }
    inline int id(int x,int y)
    {
    	return (x-1)*n+y;
    }
    inline bool spfa()
    {
    	for(int i=s;i<=t;i++) dis[i]=change[i]=inf,vis[i]=0;
    	q.push(s);
    	dis[s]=0;
    	while(!q.empty())
    	{
    		int tp=q.front(); q.pop();
    		vis[tp]=false;
    		for(nod i=head[tp];i;i=i->nxt)
    		{
    			if(dis[i->to]>dis[tp]+i->dis&&i->can>0)
    			{
    				dis[i->to]=dis[tp]+i->dis;
    				change[i->to]=std::min(change[tp],i->can);
    				road[i->to]=i;
    				if(!vis[i->to]) vis[i->to]=true,q.push(i->to);
    			}
    		}
    	}
    	return change[t]!=inf;
    }
    inline void mcmf()
    {
    	int cost=0;
    	while(spfa())
    	{
    		cost+=change[t]*dis[t];
    		for(int o=t;o!=s;o=road[o]->rev->to)
    		{
    			road[o]->can-=change[t];
    			road[o]->rev->can+=change[t];
    		}
    	}
    	printf("%d",cost);
    }
    int main()
    { 
    	n=in(),k=in(),a=in(),b=in(),c=in();
    	s=0,t=n*n*(k+1)+1,max=n*n;
    	link(s,id(1,1),0,1);
    	for(int i=0;i<=k;i++) link(id(n,n)+max*i,t,0,1);
    	for(int i=0;i<=k;i++) link(n*n+max*i,t,0,1);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    		{
    			int now=id(i,j);
    			if(in())
    			{
    				for(int u=0;u<=k-1;u++)
    					for(int v=0;v<4;v++)
    					{
    						int xx=i+rx[v];
    						int yy=j+ry[v];
    						if(xx>=1&&xx<=n&&yy>=1&&yy<=n)
    						{
    							if(v<=1) link(id(xx,yy)+u*max,now,b+a,1);
    							else link(id(xx,yy)+u*max,now,a,1);
    						}
    					}
    			}
    			else
    			{
    				for(int u=1;u<=k;u++) link(now+max*u,now,a+c,1);
    				for(int u=0;u<=k-1;u++)
    					for(int v=0;v<4;v++)
    					{
    						int xx=i+rx[v];
    						int yy=j+ry[v];
    						if(xx>=1&&xx<=n&&yy>=1&&yy<=n)
    						{
    							if(v<=1) link(id(xx,yy)+u*max,now+max*(u+1),b,1);
    							else link(id(xx,yy)+u*max,now+max*(u+1),0,1);
    						}
    					}
    			}
    		}
    	mcmf();
    	return 0;
    }
    
  • 相关阅读:
    DELPHI SOKET 编程(使用TServerSocket和TClientSocket)
    DELPHI 任务栏无EXE显示
    Delphi 实现无窗口移动(详细使用WM_NCHITTEST和PtInRect API进行测试)
    ViewPager的简单使用
    delphi 网页提交按钮执行点击事件
    Delphi 获取网站验证码的图片
    Delphi 模拟网站验证码(酷,把随机文字写道图片上)
    张文木的文章都很不错,有空仔细看看
    深度RAMOS,把操作系统全部安装在内存上
    C# ASP.net 入门之简单通讯录
  • 原文地址:https://www.cnblogs.com/olinr/p/10116229.html
Copyright © 2020-2023  润新知