程序控

IPPP (Institute of Penniless Peasent-Programmer) Fellow

:: :: :: :: :: :: :: ::
 77 随笔 :: 0 文章 :: 442 评论 :: 0 引用

Background背景

Problems that process input and generate a simple "yes" or "no" answer are called decision problems. One class of decision problems, the NP-complete problems, are not amenable to general efficient solutions. Other problems may be simple as decision problems, but enumerating all possible "yes" answers may be very difficult (or at least time-consuming).

This problem involves determining the number of routes available to an emergency vehicle operating in a city of one-way streets.

The Problem问题

Given the intersections connected by one-way streets in a city, you are to write a program that determines the number of different routes between each intersection. A route is a sequence of one-way streets connecting two intersections.

Intersections are identified by non-negative integers. A one-way street is specified by a pair of intersections. For example, j k indicates that there is a one-way street from intersection j to intersection k. Note that two-way streets can be modeled by specifying two one-way streets: j k and k j.

Consider a city of four intersections connected by the following one-way streets:

0  1
0  2
1  2
2  3

There is one route from intersection 0 to 1, two routes from 0 to 2 (the routes are 0->1->2 and 0->2 ), two routes from 0 to 3, one route from 1 to 2, one route from 1 to 3, one route from 2 to 3, and no other routes.

It is possible for an infinite number of different routes to exist. For example if the intersections above are augmented by the street 3 2 , there is still only one route from 0 to 1, but there are infinitely many different routes from 0 to 2. This is because the street from 2 to 3 and back to 2 can be repeated yielding a different sequence of streets and hence a different route. Thus the route 0->2->3->2->3->2 is a different route than 0->2->3->2.

The Input输入

The input is a sequence of city specifications. Each specification begins with the number of one-way streets in the city followed by that many one-way streets given as pairs of intersections. Each pair j k represents a one-way street from intersection j to intersection k. In all cities, intersections are numbered sequentially from 0 to the "largest" intersection. All integers in the input are separated by whitespace. The input is terminated by end-of-file.

There will never be a one-way street from an intersection to itself. No city will have more than 30 intersections.

The Output输出

For each city specification, a square matrix of the number of different routes from intersection j to intersection k is printed. If the matrix is denoted M, then M[j][k] is the number of different routes from intersection j to intersection k. The matrix M should be printed in row-major order, one row per line. Each matrix should be preceded by the string "matrix for city k" (with k appropriately instantiated, beginning with 0).

If there are an infinite number of different paths between two intersections a -1 should be printed. DO NOT worry about justifying and aligning the output of each matrix. All entries in a row should be separated by whitespace.

Sample Input输入示例

7 0 1 0 2 0 4 2 4 2 3 3 1 4 3
5
0 2
0 1 1 5 2 5 2 1
9
0 1 0 2 0 3
0 4 1 4 2 1
2 0
3 0
3 1

Sample Output输出示例

matrix for city 0
0 4 1 3 2
0 0 0 0 0
0 2 0 2 1
0 1 0 0 0
0 1 0 1 0
matrix for city 1
0 2 1 0 0 3
0 0 0 0 0 1
0 1 0 0 0 2
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
matrix for city 2
-1 -1 -1 -1 -1
0 0 0 0 1
-1 -1 -1 -1 -1
-1 -1 -1 -1 -1
0 0 0 0 0

Solution解答

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
//常量，表示可能出现的路口总数
const int nTotal = 30;
//用来存储结果的矩阵
int aMat[nTotal][nTotal];
//邻接表
//最大路口编号
int nMaxIs;
//深度遍例，每次找出由路径最后一个路口可达的所有路口
//为加快运算，方便编码，为当前路口(路径末端)的邻接表设临时变量
//循环遍例当前路口的每一个相邻路口
//从路径首个路口开始向后寻找可达路口，即检查是否已出现环
for (i = Path.begin(); i != Path.end() && *i != *iTo; ++i);
//如果找到环
if (i != Path.end()) {
//环中每个路口到它邻接的路口都有无数条路径
for (vector<int>::iterator j = i; j != Path.end(); ++j) {
aMat[*j][*j] = -1;
}
//继续下一个节点，避免对环进行深度遍例
continue;
} //若与路径中任一个路口都不直接构成环，可继续向下一级遍例
//并累计到达下一级路口的次数
++aMat[Path.front()][*iTo];
//将下一级路口加入路径
Path.push_back(*iTo);
//继续向下执行深度遍例
//本节点及其子树都遍例完毕，恢复原路径
Path.pop_back();
}
}
//主函数
int main(void) {
//循环处理输入的每一个城市交通数据
for (int nWayCnt, nCityCnt = 0; cin >> nWayCnt; ++nCityCnt) {
//清空结果矩阵和邻接表
memset(aMat, 0, sizeof(aMat));
for (int i = 0; i < nTotal; AdjTbl[i++].clear());
nMaxIs = 0;
//读入所有单行线数据，并统计出现的最大路口编号
for (int i = 0, nFrom, nTo; i < nWayCnt; ++i) {
cin >> nFrom >> nTo;
nMaxIs = max(max(nFrom, nTo), nMaxIs);
}
//查找从每个路口可到达的所有路口并发现所有在环上的路口
for (int nRoot = 0; nRoot <= nMaxIs; ++nRoot) {
vector<int> Path(1, nRoot);
}
//处理图中的环
for (int i = 0; i <= nMaxIs; ++i) {
//如果路口本身就在环上，则所有可达路口都有无数条路径
if (aMat[i][i] == -1) {
//为其所有可达路口的路径赋值为-1
for (int j = 0; j <= nMaxIs; ++j) {
aMat[i][j] = aMat[i][j] != 0 ? -1 : aMat[i][j];
}
continue;
}
//如果路口不在环上，则查找其所有可达路口是否在环上
for (int j = 0; j <= nMaxIs; ++j) {
//若可达路口j在环上，那么i至j有无数条路径
if (aMat[i][j] != 0 && aMat[j][j] == -1) {
//显然j可达的所有路口k，i也可达，且路径同样无数
for (int k = 0; k <= nMaxIs; ++k) {
aMat[i][k] = (aMat[j][k] != 0) ? -1 : aMat[i][k];
}
}
}
}
//按要求输出矩阵结果
cout << "matrix for city " << nCityCnt << endl;
for (int i = 0, j; i <= nMaxIs; ++i) {
//避免在行尾多出空格
for (j = 0; j < nMaxIs; cout << aMat[i][j++] << ' ');
cout << aMat[i][j] << endl;
}
}
return 0;
}
posted on 2010-08-17 20:01  Devymex  阅读(...)  评论(...编辑  收藏