今天终于开始看图论了。上午A了一道搜索的题,然后就开始看学的相当渣的图论,几乎就是从零开始。
先看了看树的相关知识……发现略微有些难懂。于是看了最小生成树。有几个题是用最小生成树去做的。所以又看到最小生成树。
首先关于树的一个定理:N个点用N-1条边连成一个连通块,形成的图形只可能是树。
因为N个点的图,边一定大于等于N-1,图的最小生成树(MST)就是在这些边中选出N-1条边连接所有的N个点,所得权值最小。
参考资料:信息学奥赛一本通……
最小生成树就是用来解决用最少的代价或者说长度来解决n-1条边连接n个点的问题。
Prim算法:
以一个点为进入最小生成树的点,之后依次计算其他各点到该点的权值,取最小,然后更新其余权值,循环。
蓝白点思想:白点代表已经进入最小生成树的点,蓝点代表未进入最小生成树的点。
每次循环将一个蓝点u变为白点。
通常以1为起点生成最小生成树。
以一个例题为例:
Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.
Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.
The distance between any two farms will not exceed 100,000.
4 0 4 9 21 4 0 8 17 9 8 0 16 21 17 16 0
28
源代码:(可能更直观)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#define MAX 0x7fffffff
using namespace std;
int map[10000][10000];
int visit[10000],dis[100000];
int main()
{
int n;
while(cin >> n)
{
for (int i = 1; i <= n; i++) //输入村庄的距离
for (int j = 1; j <= n; j++)
cin >> map[i][j];
memset(visit,0,sizeof(visit));
for (int i = 1; i <= n; i++)//以第一个点为起点生成最小生成树,表示后面每个点和第一个点的权值
dis[i] = map[1][i];
dis[1] = 0;
int sum = 0;
visit[1] = 1;
for (int i = 1; i <= n; i++)
{
int flag = 1;
int minn = MAX;
for (int j = 1; j <= n; j++) //找最小值
if (visit[j] != 1 && dis[j] < minn)
{
minn = dis[j];
flag = j;
}
visit[flag] = 1;
sum += dis[flag];
for (int j = 1; j <= n; j++)
if (dis[j] > map[flag][j])
dis[j] = map[flag][j];
}
cout << sum << endl;
}
return 0;
}
今天还有两道题没A一直在超时……再去弄弄这只是最基础的最小生成树……明天看Kruskal算法。。还有好多要学习的东西。。
继续努力继续努力!