危险的迷宫

【 问题描述】
近来发现了一个古老的地下迷宫,已探明该迷宫是一个 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
13

1 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

第一步:每一格分为两个顶点。为简便起见,不妨将其中一个顶点称为该格“入点”,
另一顶点称为“出点”

连一条边从“入点”指向“出点”,其流量为 1,该格的危险程度即为这条边的费用。


第二步:源点指向所有的入口格的入点,其流量均为 1,费用为 0。

所有的出口格的出点指向汇点,其流量均为 1,费用为 0。


第三步:如果两格 A、B 相通,则如下构造:

从单元格 A 的“出点”指向单元格 B 的“入点”连一条边,流量为 1,费用为 0;

从单元格 B 的“出点”指向单元格 A 的“入点”连一条边,流量为 1,费用为 0。
我们不难发现,当到达汇点的总流量与队员数,即入口(出口)数相等时,有解;否则无解。

在有解的情况下,网络流的费用实际上就是所有队员经过的格子的危险程度之和,
“最小费用”其实就是使这个总和最小。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 struct Node
  8 {
  9     int next,to,u,dis,c;
 10 } edge[1000001];
 11 int head[1001],num,n,m,k,path[1001],dist[1001],inf,ans,flow,a[101][101],q;
 12 bool vis[1001];
 13 void add(int u,int v,int dis,int c)
 14 {
 15     edge[num].next=head[u];
 16     edge[num].u=u;
 17     edge[num].dis=dis;
 18     edge[num].c=c;
 19     edge[num].to=v;
 20     head[u]=num++;
 21 }
 22 bool SPFA(int S,int T)
 23 {
 24     int i;
 25     queue<int>Q;
 26     memset(path,-1,sizeof(path));
 27     memset(dist,127/2,sizeof(dist));
 28     Q.push(S);
 29     inf=dist[0];
 30     dist[S]=0;
 31     memset(vis,0,sizeof(vis));
 32     while (Q.empty()==0)
 33     {
 34         int u=Q.front();
 35         Q.pop();
 36         vis[u]=0;
 37         for (i=head[u]; i!=-1; i=edge[i].next)
 38             if(edge[i].c>0)
 39             {
 40                 int v=edge[i].to;
 41                 if (dist[v]>dist[u]+edge[i].dis)
 42                 {
 43                     dist[v]=dist[u]+edge[i].dis;
 44                     path[v]=i;
 45                     if (vis[v]==0)
 46                     {
 47                         vis[v]=1;
 48                         Q.push(v);
 49                     }
 50                 }
 51             }
 52     }
 53     if (dist[T]==inf) return 0;
 54     return 1;
 55 }
 56 int mincost(int S,int T)
 57 {
 58     int i;
 59     while (SPFA(S,T))
 60     {
 61         int minf=inf;
 62         for (i=path[T]; i!=-1; i=path[edge[i].u])
 63         {
 64             minf=min(minf,edge[i].c);
 65         }
 66         for (i=path[T]; i!=-1; i=path[edge[i].u])
 67         {
 68             edge[i].c-=minf;
 69             edge[i^1].c+=minf;
 70         }
 71         ans+=dist[T];
 72         flow+=1;
 73     }
 74     if (flow<q) return -1;
 75     return ans;
 76 }
 77 int main()
 78 {
 79     int i,j,x1,x2,y1,y2,x,y,S,T;
 80     cin>>n>>m;
 81     memset(head,-1,sizeof(head));
 82     for (i=1; i<=n; i++)
 83     {
 84         for (j=1; j<=m; j++)
 85         {
 86             scanf("%d",&a[i][j]);
 87             add(i*m-m+j,i*m-m+j+n*m,a[i][j],1);
 88             add(i*m-m+j+n*m,i*m-m+j,-a[i][j],0);
 89         }
 90     }
 91     cin>>k;
 92     for (i=1; i<=k; i++)
 93     {
 94         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
 95         add(x1*m-m+y1+n*m,x2*m-m+y2,0,1);
 96         add(x2*m-m+y2,x1*m-m+y1+n*m,0,0);
 97         add(x2*m-m+y2+n*m,x1*m-m+y1,0,1);
 98         add(x1*m-m+y1,x2*m-m+y2+n*m,0,0);
 99     }
100     cin>>q;
101     for (i=1; i<=q; i++)
102     {
103         scanf("%d%d",&x,&y);
104         add(0,x*m-m+y,0,1);
105         add(x*m-m+y,0,0,0);
106     }
107     for (i=1; i<=q; i++)
108     {
109         scanf("%d%d",&x,&y);
110         add(x*m-m+y+n*m,2*n*m+1,0,1);
111         add(2*n*m+1,x*m-m+y+n*m,0,0);
112     }
113     S=0;
114     T=2*n*m+1;
115     printf("%d\n",mincost(S,T));
116 }

 

posted @ 2017-10-25 16:55  Z-Y-Y-S  阅读(434)  评论(0编辑  收藏  举报