您的位置:首页 > 其它

解题报告 之 ZOJ2760 How Many Shortest Path

2015-04-20 15:58 288 查看



解题报告 之 ZOJ2760 How Many Shortest Path

Description

Given a weighted directed graph, we define the shortest path as the path who has the smallest length among all the path connecting the source vertex to the target vertex. And if two path is said to be non-overlapping,
it means that the two path has no common edge. So, given a weighted directed graph, a source vertex and a target vertex, we are interested in how many non-overlapping shortest path could we find out at most.

Input

Input consists of multiple test cases. The first line of each test case, there is an integer number N (1<=N<=100), which is the number of the vertices. Then follows an N * N matrix, represents the directed
graph. Each element of the matrix is either non-negative integer, denotes the length of the edge, or -1, which means there is no edge. At the last, the test case ends with two integer numbers S and T (0<=S, T<=N-1), that is, the starting and ending points.
Process to the end of the file.

Output

For each test case, output one line, the number of the the non-overlapping shortest path that we can find at most, or "inf" (without quote), if the starting point meets with the ending.

Sample Input

4
0 1 1 -1
-1 0 1 1
-1 -1 0 1
-1 -1 -1 0
0 3
5
0 1 1 -1 -1
-1 0 1 1 -1
-1 -1 0 1 -1
-1 -1 -1 0 1
-1 -1 -1 -1 0
0 4


Sample Output

2
1


题目大意:有N个节点,构成一个有向图,给出N*N的邻接矩阵,边权值要么为非负, 要么为-1表示不邻接。再告诉你起点和终点,如果起点和终点相同输出"inf",否则问你从起点到终点一共有多少条没有公共边的最短路?

分析:这是典型的 边不相交最短路的条数 问题。用最大流解决问题。构图是其关键所在。首先我们跑一次Floyd,更新两两点之间的最短距离。然后我们就要开始建图了。大体的思路是,判断所有边是不是某条最短路上的一条边,如果是则加入到流量图中,否则抛弃,再用最大流看看有几条最短路。好了,到了这一步之后我们就该思考如何判断一条边是否是某条最短路的一部分。方法是:
dist[from][to] == dist[from][i] + path[i][j] + dist[j][to]

其中dist[i][j]表示 i 到 j 的最短路长度,而path[i][j]表示 i 到 j 的边长度。那么这个等式的意思是,f到t的某条最短路是由f到i的最短路加上j到t的最短路以及i->j这条边组成的。说明i->j
是某条最短路的一部分,那么就在流量图中加边addedge(i ,j ,1) .最后跑一下最大流看看有几条就是几条。

神坑的地方在于邻接表输入中 path[i][i] 不一定输入0 。所以必须手动将path[i][i]设置为0,否则执行最短路部分第一层判断时会出问题。因为dist[from][i] (from==i)本来应该为0,但是你不等于0就错了。

上代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const int MAXN = 310;
const int MAXM = 100100;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int to, cap, next;
};

Edge edge[MAXM];
int level[MAXN];
int head[MAXN];
int dist[MAXN][MAXN];
int path[MAXN][MAXN];
int src, des, cnt;

void addedge(int from, int to, int cap)
{
	edge[cnt].to = to;
	edge[cnt].cap = cap;
	edge[cnt].next = head[from];
	head[from] = cnt++;

	swap(from, to);

	edge[cnt].to = to;
	edge[cnt].cap = 0;
	edge[cnt].next = head[from];
	head[from] = cnt++;
}

int bfs()
{
	queue<int> q;
	while (!q.empty())
		q.pop();
	memset(level, -1, sizeof level);
	level[src] = 0;
	q.push(src);

	while (!q.empty())
	{
		int u = q.front();
		q.pop();

		for (int i = head[u]; i != -1; i = edge[i].next)
		{
			int v = edge[i].to;

			if (edge[i].cap > 0 && level[v] == -1)
			{
				level[v] = level[u] + 1;
				q.push(v);
			}
		}
	}
	return level[des] != -1;
}

int dfs(int u, int f)
{
	if (u == des)	return f;

	for (int i = head[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].to;
		if (edge[i].cap > 0 && level[v] == level[u] + 1)
		{
			int tem = dfs(v, min(f, edge[i].cap));
			if (tem > 0)
			{
				edge[i].cap -= tem;
				edge[i ^ 1].cap += tem;
				return tem;
			}
		}
	}
	level[u] = -1;
	return 0;
}

int Dinic()
{
	int ans = 0, tem;

	while (bfs())
	{
		while (tem = dfs(src, INF))
		{
			ans += tem;
		}
	}
	return ans;
}

int main()
{
	int n, from, to;
	while (cin >> n)
	{

		memset(head, -1, sizeof head);
		cnt = 0;

		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				scanf( "%d", &path[i][j] );
				dist[i][j] = path[i][j];
			}
			dist[i][i]=path[i][i]=0;
		}

		cin >> from >> to;
		from++;
		to++;
		src = from, des = to;
		if (from == to)
		{
			cout << "inf" << endl;
			continue;
		}

		for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		if ((dist[i][j] > dist[i][k] + dist[k][j] || dist[i][j] == -1) && dist[i][k] != -1 && dist[k][j] != -1)
			dist[i][j] = dist[i][k] + dist[k][j];

		if (dist[from][to] == -1)
		{
			cout << 0 << endl;
			continue;
		}

		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (dist[from][to] == dist[from][i] + path[i][j] + dist[j][to] && dist[from][to] != -1 && dist[from][i] != -1
					&& dist[i][j] != -1 && dist[j][to] != -1)
					addedge(i, j, 1);
			}
		}
		printf("%d\n", Dinic());
	}

	return 0;
}


感觉最大流的难度还是在于建图。很多模型不好抽象。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: