【费用流】危险的迷宫

【问题】
    近来发现了一个古老的地下迷宫,已探明该迷宫是一个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 420 30 40 3030 60 20 2020 15 20 20131 1 2 11 2 1 31 2 2 21 3 1 41 4 2 4
2 1 2 22 1 3 12 2 2 32 3 2 42 4 3 43 1 3 23 2 3 33 3 3 421 11 22 33 4


【输出样例】

235




noip前的题……我现在终于写对了…………


很水的拆点网络流……每个点拆成入点和出点然后入口和S相通出口和T相通就行了……然后最小费用最大流就行了


调的时候迷之WA是因为加边又加错了 = = 翔爷查了没多久就查出来了果然是大神OTL…………


建图的时候一定要注意。。( (x - 1) * B + y) ←这是是*B不是*A。。。



#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

const int inf = 0x3f3f3f;

int A, B, K, N;
int map[15][15];
int S, T;
int ans;

struct ed
{
	int v, w, flow, next;
}e[35*35*8];

int k, head[35*35*4];

inline void adde(int u, int v, int f, int w)
{
	e[k] = (ed){v, w, f, head[u]};
	head[u] = k++;
	e[k] = (ed){u, -w, 0, head[v]};
	head[v] = k++;
}

inline int in(int x, int y) 
{ 
	return ( ( (x - 1) * B + y) << 1 ) - 1; 
}

inline int out(int x, int y) 
{ 
	return ( (x - 1) * B + y) << 1; 
}

inline void build_map()
{
	memset(head, -1, sizeof(head));
	
	for(int i = 1; i <= A; ++i)
	{
		for(int j = 1; j <= B; ++j)
		{
			scanf("%d", &map[i][j]);
			adde(in(i, j), out(i, j), 1, map[i][j]);
		}
	}
	
	S = 0; T = out(A, B) + 1;
	
	cin >> K;
	
	int x1, x2, y1, y2;
	for(int i = 1; i <= K; ++i)
	{
		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
		adde(out(x1, y1), in(x2, y2), 1, 0);
		adde(out(x2, y2), in(x1, y1), 1, 0);
	}
	
	cin >> N;
	
	for(int i = 1; i <= N; ++i)
	{
		scanf("%d%d", &x1, &y1);
		adde(S, in(x1, y1), 1, 0);
	}
	for(int i = 1; i <= N; ++i)
	{
		scanf("%d%d", &x1, &y1);
		adde(out(x1, y1), T, 1, 0);
	}
}

int dis[35*35*4];
bool vis[35*35*4];
int pre[35*35*4]; 
int deltaf, flow;

queue <int> q;

bool spfa()
{
	memset(dis, inf, sizeof(dis));
	deltaf = inf;
	
	//printf("%d\n",dis[S]); 
	
	dis[S] = 0;
	q.push(S);
	
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		vis[u] = 0;
		
		for(int i = head[u]; ~i; i = e[i].next)
		{
			int v = e[i].v;
			
			if(e[i].flow && dis[v] > dis[u] + e[i].w)
			{
				dis[v] = dis[u] + e[i].w;
				pre[v] = i;
				deltaf = min(e[i].flow, deltaf);
		
				if(!vis[v])
				{
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
	
	return dis[T] < inf;
}

int main()
{
	freopen("maze.in", "r", stdin);
	freopen("maze.out", "w", stdout);
	
	cin >> A >> B;
	
	build_map();
	
	bool flag = 0;
	while(spfa())
	{
		flag = 1;
		for(int i = T; i != S; i = e[pre[i] ^ 1].v)
		{
			e[pre[i]].flow -= deltaf;
			e[pre[i] ^ 1].flow += deltaf;
		}
		
		flow += deltaf;
		ans += deltaf * dis[T];
	}
	
	if(flow >= N) cout << ans << endl;
	else puts("-1");
	
	return 0;
}

之前查错是对着小明的代码查错的…………嗯…………也贴上来吧免得以后找不到了…………其实还是想说java风看着好肉疼…………


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
//Global Variables & Definetions
int A,B,K,N;
int map[110][110];

#define MS(arr,x) memset(arr,x,sizeof(arr))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
//End Global Variables & Definetions

//Network Flow!
	//map
#define num(x,y) (((x) * B) + y)
#define in(x,y) num(x,y)
#define out(x,y) (num(x,y) + A * B)

#define S  209
#define SS 210
#define T  211

int h[220];
struct edge {
	int v,next;
	int cap,flow;
	int cost;
}e[10000];

int ecnt = -1;
inline void _add(int u, int v, int cap, int cost) {
	ecnt++;
	e[ecnt].v = v;
	e[ecnt].cap = cap;
	e[ecnt].cost = cost;
	e[ecnt].flow = 0;
	e[ecnt].next = h[u];
	h[u] = ecnt;
}

inline void adde(int u, int v, int cap, int cost) {
	_add(u, v, cap, cost);
	_add(v, u,  0, -cost);
}

void clear() {
	memset(h, -1, sizeof(h));
	ecnt = -1;
}
	//End Map
	
	//SPFA
queue<int> q;
int inq[220];
int dis[220], f[220], fe[220], maxf[220];

inline void init_spfa() {
	while(!q.empty()) q.pop();
	MS(inq,0);MS(dis,0x3f);
	
	dis[S] = 0;
	f[S] = fe[S] = -1;
	maxf[S] = 0x7fffffff;
	inq[S] = 1;
	q.push(S);
}
	//End SPFA
int maxflow() {
	int ans = 0,flow = 0;
	bool flag;
	
	do {
		init_spfa();
		flag = 0;
		
		while(!q.empty()) {
			int u = q.front();q.pop();
			inq[u] = 0;
			
			for(int i = h[u];i != -1;i = e[i].next) if(e[i].flow < e[i].cap) {
				int v = e[i].v;
				
				if(dis[v] > dis[u] + e[i].cost) {
					dis[v] = dis[u] + e[i].cost;
					fe[v] = i;f[v] = u;
					maxf[v] = min(maxf[u] ,e[i].cap - e[i].flow);
					
					if(!inq[v]) {
						q.push(v);
						inq[v] = 1; 
					}
				}
			}
		}
		
		if(dis[T] < 0x3f3f3f3f) {
			flag = 1;
			ans  += dis[T] * maxf[T];
			flow += maxf[T];
			
			for(int ptr = T;f[ptr] != -1;ptr = f[ptr]) {
				int fa = fe[ptr];
				e[fa].flow += maxf[T];
				e[fa ^ 1].flow -= maxf[T];
			}
		}
	} while(flag);
	
	if(flow < N) return -1;
	else return ans;
}
//End Network Flow!

//Main Structure
inline void ir() {
	clear();
	freopen("maze.in","r",stdin);
	freopen("maze.out","w",stdout);
	
	scanf("%d%d",&A,&B);
	for(int i = 0;i < A;i++) {
		for(int j = 0;j < B;j++) {
			scanf("%d",&map[i][j]);
			adde(in(i,j), out(i,j), 1, map[i][j]);
		}
	}
	
	scanf("%d",&K);
	int X0,Y0,X1,Y1;
	for(int i = 0;i < K;i++) {
		scanf("%d%d%d%d",&X0,&Y0,&X1,&Y1);
		adde(out(X0 - 1,Y0 - 1), in(X1 - 1,Y1 - 1), 1, 0);
		adde(out(X1 - 1,Y1 - 1), in(X0 - 1,Y0 - 1), 1, 0);
	}
	
	scanf("%d",&N);
	for(int i = 0;i < N;i++) {
		scanf("%d%d",&X0,&Y0);
		adde(SS, in(X0 - 1,Y0 - 1), 1, 0);
	}
	for(int i = 0;i < N;i++) {
		scanf("%d%d",&X1,&Y1);
		adde(out(X1 - 1,Y1 - 1), T, 1, 0);
	}
	
	adde(S, SS, N, 0);
}

int main() {
	ir();
	
	printf("%d\n",maxflow());
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值