题目描述
近来发现了一个古老的地下迷宫,已探明该迷宫是一个A行B列的矩阵,该迷宫有N个不同的出口与N个不同的入口,任一单元格不会既为入口又为出口。为了进一步探明与发掘该迷宫,N个考古队员分别从地上的N个不同的入口进入迷宫,并且计划从N个不同的出口出来。每个队员任意选择一个出口出来,但任意两名队员不会选择同一个出口。
迷宫中的每一格与其相邻的某些格相通。该迷宫设计非常精妙,在不知道具体机关的情况下,人一旦离开其所在格后,该格将迅速关闭,且再也不能开启,也就是说每一格仅能进入一次。更糟的是,迷宫中的每一格都有一定的危险性,专家们用1至100的整数表示,数值越大表示越危险。正因为如此,再加之每一格都不很宽敞,两人一起进入比较危险,所以规定不能两个人同时进入同一格。
为了队员们的安全着想,希望你能够编程求出如何使队员们所经过单元格的危险性总和最小。
【样例解释】
有如下迷宫:
每一格中的数字表示该格的危险程度。两格间若有空缺,表示这两格相通。
入口有两个:(1,1)即第一行第一列,(1,2)即第一行第二列
出口也有两个:(2,3)即第二行第三列,(3,4)即第三行第四列
两名队员的最好的行动方案之一,如上图红蓝箭头所示。危险程度之和最小为235。
数据范围
A,B<=10
样例输入
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
解题思路
这道题需要保证每个格子只经过一次,所以最好要拆点
反正我没拆点WA了
对于A点与B点连通,则A的出点连向B的入点,B的出点连向A的入点,权值1,费用0
每个点的入点连向出点,权值1,费用为危险值
源点向入口连边,权值1,费用0
出口向汇点连边,权值1,费用0
最小费用流
get233
代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#define Maxn 233333
#define Maxe 233333
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int A,B,S=0,T,vl[105];
int n,m,k,cnt=0,h[Maxn],dis[Maxn],pre[Maxn],preto[Maxn],vis[Maxn];
struct node{int to,next,v,k,pair;}e[Maxe];
void AddEdge(int x,int y,int v,int kk,int pair){e[cnt]=(node){y,h[x],v,kk,pair};h[x]=cnt;}
void AddEdge(int x,int y,int v,int kk){AddEdge(x,y,v,kk,++cnt+1);AddEdge(y,x,0,-kk,++cnt-1);}
bool SPFA(){
queue<int>Q;
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(pre,0,sizeof(pre));
memset(preto,0,sizeof(preto));
dis[S]=0;
vis[S]=1;
Q.push(S);
while(Q.size()){
int x=Q.front();
Q.pop();
vis[x]=false;
for(int p=h[x];p;p=e[p].next){
int y=e[p].to;
if(e[p].v&&dis[y]>dis[x]+e[p].k){
pre[y]=p;
preto[y]=x;
dis[y]=dis[x]+e[p].k;
if(!vis[y])Q.push(y);
}
}
}
return dis[T]<=(1<<29);
}
int Adjust(){
int flow=1<<30;
for(int p=T;p!=S;p=preto[p])
flow=min(flow,e[pre[p]].v);
for(int p=T;p!=S;p=preto[p]){
e[pre[p]].v-=flow;
e[e[pre[p]].pair].v+=flow;
}
return dis[T]*flow;
}
int Solve(){
int Ans=0,tot=0;
while(SPFA())Ans+=Adjust(),tot++;
return Ans*(tot==n);
}
void Init(){
A=Getint();
B=Getint();
for(int i=1;i<=A;i++)
for(int j=1;j<=B;j++)
vl[(i-1)*B+j]=Getint();
k=Getint();
S=0,T=2*A*B+1;
for(int i=1;i<=A*B;i++){
AddEdge(2*i-1,2*i,1,vl[i]);
}
for(int i=1;i<=k;i++){
int x1=Getint(),y1=Getint(),p1=(x1-1)*B+y1;
int x2=Getint(),y2=Getint(),p2=(x2-1)*B+y2;
AddEdge(p1*2,p2*2-1,1,0);
AddEdge(p2*2,p1*2-1,1,0);
}
n=Getint();
for(int i=1;i<=n;i++){
int x=Getint(),y=Getint(),p=(x-1)*B+y;
AddEdge(S,p*2-1,1,0);
}
for(int i=1;i<=n;i++){
int x=Getint(),y=Getint(),p=(x-1)*B+y;
AddEdge(2*p,T,1,0);
}
}
int main(){
Init();
int Ans;
cout<<((Ans=Solve())?Ans:-1);
return 0;
}