zoukankan      html  css  js  c++  java
  • 危险的迷宫 网络流

    【 问题描述】
    近来发现了一个古老的地下迷宫,已探明该迷宫是一个 A 行 B 列的矩阵,该迷宫有 N
    个不同的出口与 N 个不同的入口,任一单元格不会既为入口又为出口。为了进一步探明与
    发掘该迷宫,N 个考古队员分别从地上的 N 个不同的入口进入迷宫,并且计划从 N 个不同
    的出口出来。每个队员任意选择一个出口出来,但任意两名队员不会选择同一个出口。
    迷宫中的每一格与其相邻的某些格相通。该迷宫设计非常精妙,在不知道具体机关的情
    况下,人一旦离开其所在格后,该格将迅速关闭,且再也不能开启,也就是说每一格仅能进
    入一次。更糟的是,迷宫中的每一格都有一定的危险性,专家们用 1 至 100 的整数表示,数
    值越大表示越危险。正因为如此,再加之每一格都不很宽敞,两人一起进入比较危险,所以
    规定不能两个人同时进入同一格。
    为了队员们的安全着想,希望你能够编程求出如何使队员们所经过单元格的危险性总和
    最小。
    有如下迷宫:
    每一格中的数字表示该格的危险程度。两格间若有空缺,表示这两格相通。
    入口有两个:
    (1,1)即第一行第一列,(1,2)即第一行第二列
    出口也有两个:
    (2,3)即第二行第三列,
    (3,4)即第三行第四列
    两名队员的最好的行动方案之一,如上图红蓝箭头所示。危险程度之和最小为 235。
    【输入描述】
    第一行是两个整数 A 与 B(1≤A,B≤10),中间用空格分隔,表示该迷宫是 A 行 B 列的。
    第 2 行至第 A+1 行,每行有 B 个 1 至 100 以内的整数,表示该迷宫每一格的危险程度。
    以下一行是一个整数 K。接着 K 行每行有四个整数 X0,Y0,X1,Y1,(1 ≤X0,X1≤A, 1≤Y0,Y1
    ≤B) ,表示(X0,Y0),(X1,Y1)为相邻的两格,这两格互相相通。


    接着一行是一个整数 N(0≤N≤A*B/2)
    ,表示有 N 个出口与入口,保证出入口不会重
    合。
    以下 N 行,每行有两个整数 X0,Y0,表示每个入口的行列位置。
    以下还有 N 行,每行有两个整数 X1,Y1,表示每个出口的行列位置。
    【输出描述】
    输出仅一个数,若队员们不能全部到达指定目标位置,则输出-1;否则输出所有队员所
    经过的所有单元格的危险程度之和。
    【输入样例】
    3 4
    20 30 40 30
    30 60 20 20
    20 15 20 20
    131 1 2 1
    1 2 1 3
    1 2 2 2
    1 3 1 4
    1 4 2 4
    2 1 2 2
    2 1 3 1
    2 2 2 3
    2 3 2 4
    2 4 3 4
    3 1 3 2
    3 2 3 3
    3 3 3 4
    2
    1 1
    1 2
    2 3
    3 4
    【输出样例】
    235


    这其实是一道最小费用最大流的‘模板题’.

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    
    #define ll long long
    #define il inline
    #define db double
    
    using namespace std;
    
    il int gi()
    {
    	int x=0,y=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')
    		{
    			if(ch=='-')
    				y=-1;
    			ch=getchar();
    		}
    	while(ch>='0'&&ch<='9')
    		{
    			x=x*10+ch-'0';
    			ch=getchar();
    		}
    	return x*y;
    }
    
    int n,m;
    
    int src,des;
    
    int head[200045],cnt=1;
    
    struct edge
    {
    	int next,to,cap,cost;
    }e[200045];
    
    il void add(int from,int to,int cap,int cost)
    {
    	e[++cnt].next=head[from];
    	e[cnt].to=to;
    	e[cnt].cap=cap;
    	e[cnt].cost=cost;
    	head[from]=cnt;
    }
    
    int map[45][45];
    
    il int get_node(int x,int y)
    {
    	return (x-1)*m+y;
    }
    
    il void build(int from,int to,int cap,int cost)//将双向边
    {
    	add(from,to,cap,cost);//正边
    	add(to,from,0,-cost);//负边
    }
    
    int ans;
    
    int flow;
    
    int t[100045];
    
    int headd,tail;
    
    bool vis[100045];
    
    int dist[100045],pre[100045];//pre保存边的编号
    
    il bool bfs()
    {
    	memset(dist,127/3,sizeof(dist));
    	headd=0,tail=1;
    	t[0]=src;
    	dist[src]=0;
    	vis[src]=1;
    	while(headd!=tail)
    		{
    			int h=t[headd++];
    			vis[h]=0;
    			int r=head[h];
    			while(r!=-1)
    				{
    					int now=e[r].to;
    					if(dist[now]>dist[h]+e[r].cost&&e[r].cap>0)
    						{
    							dist[now]=dist[h]+e[r].cost;
    							pre[now]=r;
    							if(!vis[now])
    								{
    									vis[now]=1;
    									t[tail++]=now;
    								}
    						}
    					r=e[r].next;
    				}
    		}
    	if(dist[des]!=dist[100000])
    		return 1;
    	else
    		return 0;
    }
    
    il void back()
    {
    	int now=des;
    	while(now!=src)
    		{
    			ans+=e[pre[now]].cost;
    			e[pre[now]].cap--;
    			e[pre[now]^1].cap++;
    			now=e[pre[now]^1].to;
    		}
    }
    
    il void min_flow()
    {
    	while(bfs())//可以跑到终点
    		{
    			back();//把路上的边都更新
    			flow++;
    		}
    }
    
    int main()
    {
    	freopen("maze.in","r",stdin);				
    	freopen("maze.out","w",stdout);
    
    	memset(head,-1,sizeof(head));
    
    	n=gi(),m=gi();
    
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			{
    				map[i][j]=gi();
    				build(get_node(i,j),get_node(i,j)+n*m,1,map[i][j]);//拆点建边
    			}
    
    	int k=gi();
    	int x1,y1,x2,y2;
    	for(int i=1;i<=k;i++)
    		{
    			x1=gi(),y1=gi(),x2=gi(),y2=gi();
    			build(get_node(x1,y1)+n*m,get_node(x2,y2),1,0);
    			build(get_node(x2,y2)+n*m,get_node(x1,y1),1,0);
    		}
    
    	int q=gi();
    	int x,y;
    	src=0,des=n*m*2+1;
    	for(int i=1;i<=q;i++)
    		{
    			x=gi(),y=gi();
    			build(src,get_node(x,y),1,0);
    		}
    	
    	for(int i=1;i<=q;i++)
    		{
    			x=gi(),y=gi();
    			build(get_node(x,y)+n*m,des,1,0);
    		}
    
    	min_flow();//跑费用流
    	
    	if(flow==q)
    		printf("%d
    ",ans);
    	else
    		printf("-1
    ");
    
    	return 0;
    }
    
  • 相关阅读:
    Ajax学习网址收集
    Crystal Report Download URL and SN
    svn eclipse unable to load default svn client的解决办法
    Effective C++:条款08:别让异常逃离析构函数 (Prevent exceptions from leaving destructors.)
    Effective C++:条款07:为多态基类声明virtual析构函数 (Declare destructors virtual in polymorphic base classes.)
    Effective C++:条款06:若不想使用编译器自动生成的函数,就该明确拒绝 (Explicitly disallow the use of compliergenerated functions you do not want.)
    #define高级教程
    Effective C++:条款04:确定对象被使用前已先被初始化 (Make sure that objects are initialized before they're used.)
    Effective C++:条款05:了解C++默默编写并调用哪些函数 (Know what functions C++ silently writes and calls.)
    Linq 调用存储过程(转)
  • 原文地址:https://www.cnblogs.com/gshdyjz/p/7729671.html
Copyright © 2011-2022 走看看