图模型2--2022-5-13

zoj 2797

PTA2797
*~~

106 miles to Chicago

~~ *
Time Limit: 5000 msMemory Limit: 32768 KB

In the movie “Blues Brothers”, the orphanage where Elwood and Jack were raised may be sold to the Board of Education if they do not pay 5000 dollars in taxes at the Cook Country Assessor’s Office in Chicago. After playing a gig in the Palace Hotel ballroom to earn these 5000 dollars, they have to find a way to Chicago. However, this is not so easy as it sounds, since they are chased by the Police, a country band and a group of Nazis. Moreover, it is 106 miles to Chicago, it is dark and they are wearing sunglasses.
As they are on a mission from God, you should help them find the safest way to Chicago. In this problem, the safest way is considered to be the route which maximises the probability that they are not caught.

Input Specification

The input file contains several test cases.
Each test case starts with two integers n and m (2 ≤ n ≤ 100 , 1 ≤ m ≤ n*(n-1)/2). n is the number of intersections, m is the number of streets to be considered.
The next m lines contain the description of the streets. Each street is described by a line containing 3 integers a, b and p (1 ≤ a, b ≤ n , a ≠ b, 1 ≤ p ≤ 100): a and b are the two end points of the street and p is the probability in percent that the Blues Brothers will manage to use this street without being caught. Each street can be used in both directions. You may assume that there is at most one street between two end points.
The last test case is followed by a zero.

Output Specification

For each test case, calculate the probability of the safest path from intersection 1 (the Palace Hotel) to intersection n (the Honorable Richard J. Daley Plaza in Chicago). You can assume that there is at least one path between intersection 1 and n.
Print the probability as a percentage with exactly 6 digits after the decimal point. The percentage value is considered correct if it differs by at most 10-6 from the judge output. Adhere to the format shown below and print one line for each test case.

Sample Input

5 7
5 2 100
3 5 80
2 3 70
2 1 50
3 4 90
4 1 85
3 1 70
0

Sample Output

61.200000 percent

在这里插入图片描述

板子题,标准迪杰斯特拉算法。

求最短路径长度,注意路径数组的初始化工作。(因为没初始化,导致第二次之后都出错了)

#include<iostream>
#include<string.h>
#include<iomanip>
using namespace std;

const int maxn = 100;
double map[maxn][maxn];
double dist[maxn];
int main()
{
	memset(map, 0, sizeof(map));
	int n, m,i,a,b,p,j;
	while (cin >> n && n)
	{
		
		cin >> m;
		for (i = 0; i < m; i++)
		{
			cin >> a >> b >> p;
			map[a][b] = p;
			map[b][a] = p;
		}
		map[1][1] = 1;
		for (i = 1; i < maxn; i++)
		{
			dist[i] = map[1][i];
		}
		int x = 0;
		double s = 0;
		for (i = 0; i < n - 1; i++)
		{
			s = 0;
			for (j = 1; j <= n; j++)
				if (!map[j][j] && dist[j] >= s)
				   s = dist[x = j];  //找一个最大点,x 作为过渡点
			map[x][x] = 1;
			for (j = 1; j <= n; j++)
			{
				dist[j] = dist[j] > map[x][j] * s / 100.0 ? dist[j] : map[x][j] * s / 100.0;
			}
		}
		cout << setiosflags(ios::fixed) << setprecision(6) << dist[n] << " percent" << endl;
	}
	return 0;
}

其实上面的思路只适用于非负数的边长

当图中出现负数边,以上方法就不适用了。

在这里插入图片描述

迪杰斯特拉的板子

在这里插入图片描述

用优先队列改进


struct Distance
{
	int dis;
	int start;
	int end;
}dist[m];

bool operator<(const Distance& a, const Distance& b)
{
	if (a.dis > b.dis) return true; else return false;
}

priority_queue<Distance> PQ;

负数边的问题

在这里插入图片描述

bellman ford算法

分析:如果存在最短路径,只有n-1条边,只需要n-1次迭代
每个节点最多经过一次。
通过限制次数达到不重复走边的情况。

在这里插入图片描述在这里插入图片描述

bellman_ford 算法可以看成是对有无最短路径的一个判断

如果存在负数圈,则没有最短路径

#include<iostream>  
#include<cstdio>  
using namespace std;  
  
#define MAX 0x3f3f3f3f  
#define N 1010  
int nodenum, edgenum, original; //点,边,起点  
  
typedef struct Edge //边  
{  
    int u, v;  
    int cost;  
}Edge;  
  
Edge edge[N];  
int dis[N], pre[N];  
  
bool Bellman_Ford()  
{  
    for(int i = 1; i <= nodenum; ++i) //初始化  
        dis[i] = (i == original ? 0 : MAX);  
    for(int i = 1; i <= nodenum - 1; ++i)  
        for(int j = 1; j <= edgenum; ++j)  
            if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)  
            {  
                dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;  
                pre[edge[j].v] = edge[j].u;  
            }  
            bool flag = 1; //判断是否含有负权回路  
            for(int i = 1; i <= edgenum; ++i)  
                if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)  
                {  
                    flag = 0;  
                    break;  
                }  
                return flag;  
}  
  
void print_path(int root) //打印最短路的路径(反向)  
{  
    while(root != pre[root]) //前驱  
    {  
        printf("%d-->", root);  
        root = pre[root];  
    }  
    if(root == pre[root])  
        printf("%d\n", root);  
}  

#学会手工的方法去做 bellman-ford改进算法

在这里插入图片描述手工做法步骤:
每次找出发点,以及他能到达的所有点的边。
根据这些边找最小的边,把到达的点的数字标为这个边的长度。
重复上述步骤。

第一次最小是到V3点,距离是-1
在这里插入图片描述第二次也是到-3,重新赋值为0

在这里插入图片描述第三次发现V5,和V6一样,则都赋值为6、

在这里插入图片描述

在这里插入图片描述

练习 ZOJ 1221

zoj1221

**

Risk

**
Time Limit: 2000 msMemory Limit: 65536 KB

Risk is a board game in which several opposing players attempt to conquer the world. The gameboard consists of a world map broken up into hypothetical countries. During a player’s turn, armies stationed in one country are only allowed to attack only countries with which they share a common border. Upon conquest of that country, the armies may move into the newly conquered country.

During the course of play, a player often engages in a sequence of conquests with the goal of transferring a large mass of armies from some starting country to a destination country. Typically, one chooses the intervening countries so as to minimize the total number of countries that need to be conquered. Given a description of the gameboard with 20 countries each with between 1 and 19 connections to other countries, your task is to write a function that takes a starting country and a destination country and computes the minimum number of countries that must be conquered to reach the destination. You do not need to output the sequence of countries, just the number of countries to be conquered including the destination. For example, if starting and destination countries are neighbors, then your program should return one.

The following connection diagram illustrates the sample input.

Input

Input to your program will consist of a series of country configuration test sets. Each test set will consist of a board description on lines 1 through 19. The representation avoids listing every national boundary twice by only listing the fact that country I borders country J when I < J. Thus, the Ith line, where I is less than 20, contains an integer X indicating how many “higher-numbered” countries share borders with country I, then X distinct integers J greater than I and not exceeding 20, each describing a boundary between countries I and J. Line 20 of the test set contains a single integer (1 <= N <= 100) indicating the number of country pairs that follow. The next N lines each contain exactly two integers (1 <= A,B <= 20; A!=B) indicating the starting and ending countries for a possible conquest.

There can be multiple test sets in the input; your program should continue reading and processing until reaching the end of file. There will be at least one path between any two given countries in every country configuration.

Output

For each input set, your program should print the following message “Test Set #T” where T is the number of the test set starting with 1. The next NT lines each will contain the result for the corresponding test in the test set - that is, the minimum number of countries to conquer. The test result line should contain the start country code A the string " to " the destination country code B ; the string ": " and a single integer indicating the minimum number of moves required to traverse from country A to country B in the test set. Following all result lines of each input set, your program should print a single blank line.

Sample Input

1 3
2 3 4
3 4 5 6
1 6
1 7
2 12 13
1 8
2 9 10
1 11
1 11
2 12 17
1 14
2 14 15
2 15 16
1 16
1 19
2 18 19
1 20
1 20
5
1 20
2 9
19 5
18 19
16 20

Sample Output

Test Set #1
1 to 20: 7
2 to 9: 5
19 to 5: 6
18 to 19: 2
16 to 20: 2

问题是: 题目意思是把每次图都要更新一次。重新算距离

floyd就是3个for循环了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int e[21][21];
const int inf = 999999;
void init()
{
	int i, j;
	for (i = 1; i <= 20; i++)
	{
		for (j = 1; j <= 20; j++)
		{
			if (i == j)
				e[i][j] = 0;
			else
				e[i][j] = inf;
		}
	}
}
void floyd()
{
	int i, j, k;
	for (k = 1; k <= 20; k++)
	{
		for (i = 1; i <= 20; i++)
		{
			for (j = 1; j <= 20; j++)
			{
				if (e[i][j] > e[i][k] + e[k][j])
					e[i][j] = e[i][k] + e[k][j];
			}
		}
	}
}
int main()
{
	int i, j, u, v, x;
	int n, m;
	int num = 1;
	while (cin>>n)
	{
		init();
		for (i = 1; i <= n; i++)
		{
			cin >> x;
			e[1][x] = e[x][1] = 1;
		}
		for (i = 2; i <= 19; i++)
		{
			cin >> n;
			for (j = 1; j <= n; j++)
			{
				cin >> x;
				e[i][x] = e[x][i] = 1;
			}
		}
		floyd();
		printf("Test Set #%d\n", num++);
		cin >> m;
		for (i = 1; i <= m; i++)
		{
			cin >> u >> v;
			printf("%d to %d: %d\n", u, v, e[u][v]);
		}
		cout << endl;
	}
	return 0;
}
/*
1 3
2 3 4
3 4 5 6
1 6
1 7
2 12 13
1 8
2 9 10
1 11
1 11
2 12 17
1 14
2 14 15
2 15 16
1 16
1 19
2 18 19
1 20
1 20
5
1 20
2 9
19 5
18 19
16 20

*/

在这里插入图片描述

作业1942

PTA——zoj 1942
Frogger
Time Limit: 2000 msMemory Limit: 65536 KB

Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sitting on another stone. He plans to visit her, but since the water is dirty and full of tourists’ sunscreen, he wants to avoid swimming and instead reach her by jumping.

Unfortunately Fiona’s stone is out of his jump range. Therefore Freddy considers to use other stones as intermediate stops and reach her by a sequence of several small jumps.

To execute a given sequence of jumps, a frog’s jump range obviously must be at least as long as the longest jump occuring in the sequence.
The frog distance (humans also call it minimax distance) between two stones therefore is defined as the minimum necessary jump range over all possible paths between the two stones.

You are given the coordinates of Freddy’s stone, Fiona’s stone and all other stones in the lake. Your job is to compute the frog distance between Freddy’s and Fiona’s stone.

Input

The input will contain one or more test cases. The first line of each test case will contain the number of stones n (2 <= n <= 200). The next n lines each contain two integers xi, yi (0 <= xi, yi <= 1000) representing the coordinates of stone #i. Stone #1 is Freddy’s stone, stone #2 is Fiona’s stone, the other n-2 stones are unoccupied. There’s a blank line following each test case. Input is terminated by a value of zero (0) for n.

Output

For each test case, print a line saying “Scenario #x” and a line saying “Frog Distance = y” where x is replaced by the test case number (they are numbered from 1) and y is replaced by the appropriate real number, printed to three decimals. Put a blank line after each test case, even after the last one.

Sample Input

2
0 0
3 4

3
17 4
19 4
18 5

0

Sample Output

Scenario #1
Frog Distance = 5.000

Scenario #2
Frog Distance = 1.414

Your job is to compute the frog distance between Freddy’s and Fiona’s stone.

The frog distance (humans also call it minimax distance) between two stones therefore is defined as the minimum necessary jump range over all possible paths between the two stones.

本题是找到跳跃的最短路径就行,不是两个点之间的距离。

在这里插入图片描述

#include<string.h>
#include<iostream>
#include <cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define maxnum 300
#define inf 0x3f3f3f3f
using namespace std;
int x[maxnum], y[maxnum], n;
double map[maxnum][maxnum];
void floyd()
{
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
            {
                map[i][j] = min(map[i][j], max(map[i][k], map[k][j]));//许多通路中最长边中的最小边
            }
}
int main()
{
    int q = 1;
    while (cin>>n && n)
    {
        mem(map, 0);
        for (int i = 1; i <= n; i++)
            cin>>x[i]>>y[i];
        for (int i = 1; i <= n; i++)
            for (int j = i + 1; j <= n; j++)
                map[i][j] = map[j][i] = sqrt(double(x[i] - x[j]) * (x[i] - x[j]) + double(y[i] - y[j]) * (y[i] - y[j]));
        floyd();
        printf("Scenario #%d\nFrog Distance = %.3lf\n\n", q++, map[1][2]);
    }
    return 0;
}

1091 骑士周游,用最短路径方法求解,需要怎么做,怎么样把图模型进行存储。

Knight Moves
Time Limit: 2000 msMemory Limit: 65536 KB

A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.
Of course you know that it is vice versa. So you offer him to write a program that solves the “difficult” part.

Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
Input Specification

The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.
Output Specification

For each test case, print one line saying “To get from xx to yy takes n knight moves.”.
Sample Input

e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6

Sample Output

To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.

骑士骑着马,只能走日字,所以需要初始化路径。

关键在于,怎么把图存储。
使用邻接矩阵还是邻接表。

未完成待续

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值