【北大DS公开课】地震之后(刘朱算法-有向图上求MST)

题目:http://dsalgo.openjudge.cn/dsmoochw8/4/


做过这道题后,我明白了为何prime算法不可用于DG上的MST求解,并理解了刘朱算法的思想。感谢某匿名同学提供了很多有用的资料和Chong Wang同学的提问。

相应的帖子链接:https://class.coursera.org/dsalgo-001/forum/thread?thread_id=236


mysol:

1.构图(去掉指向顶点0的弧)

2.floodfill判断是否联通图,if not :continue

3.foreach_v if( !visit[v] ): dfs(v)【找环,压缩, 标记】

4.求和

/*
ID:slowlight
PROG:
LANG:C++
DATE:
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define MAXVERTEXES 100
#define MAXEDGES 10000
#define INF 100000000

#define FORI(type, i, limi) for(type i = 0;i < limi;++i)

typedef struct node_type {
	int x;
	int y;
	int pre;
}Node;

Node nodes[MAXVERTEXES + 1];
double cost[MAXVERTEXES + 1][MAXVERTEXES + 1];
bool canReach[MAXVERTEXES + 1][MAXVERTEXES + 1];

int n, m;

// Judge if the graph is a unicom plan.
bool visit[MAXVERTEXES + 1];
void floodFill(int now, int n);
bool isUnicom(int n);

//If a circle exists.
int in_node[MAXVERTEXES + 1];
vector myvec;
bool vv[MAXVERTEXES + 1];
void dfs(int now, int s);

int main()
{
	freopen("input.in", "r", stdin);
	freopen("output.out", "w", stdout);
	
	int i, j;
	int v1, v2;
	double ans;
	double tmp;
	
	while( scanf("%d%d", &n, &m) != EOF )
	{
		/* init */
		memset(cost, 0, sizeof(cost));
		memset(canReach, false, sizeof(canReach));
		memset(visit, false, sizeof(visit));
		myvec.clear();

		FORI(int, i, n)
		{
			cin >> nodes[i].x >> nodes[i].y;

			// Set i`pre itself so that any arc entering i can replace this value. 
			nodes[i].pre = i;
		}

		FORI(int, j, m)
		{
			cin >> v1 >> v2;
			v1--;
			v2--;

			if(v2 == 0)
				continue;

			canReach[v1][v2] = true;

			cost[v1][v2] = sqrt( (double)( ( nodes[v1].x - nodes[v2].x ) * ( nodes[v1].x - nodes[v2].x ) + 
				( nodes[v1].y - nodes[v2].y ) * ( nodes[v1].y - nodes[v2].y ) ) );

			if( cost[nodes[v2].pre][v2] == 0 
					|| cost[v1][v2] < cost[nodes[v2].pre][v2] )
				nodes[v2].pre = v1;
		}

		// If this is not a unicom....
		if( isUnicom(n) == false)
		{
			cout << "NO" << endl;
			continue;
		}

		// Eliminate circles.
		// Clear bool visit[],use again.
		memset(visit, false, sizeof(visit));

		FORI(int, i, n)
		{
			if( !visit[i] )
			{
				memset(vv, false, sizeof(vv));
				dfs(i, i);
			}
		}

		ans = 0;
		FORI(int, i, n)
		{
			ans += cost[nodes[i].pre][i];
		}

		printf("%.2lf\n", ans);
	}
	
	return 0;
}

void floodFill(int now, int n)
{
	visit[now] = true;

	int i;
	FORI(int, i, n)
	{
		if(canReach[now][i] == true && visit[i] == false)
			floodFill(i, n);
	}
}

bool isUnicom(int n)
{
	int i;

	// Let the flood fill...
	floodFill(0, n);
	FORI(int, i, n)
	{
		if( !visit[i] )
			return false;
	}

	return true;
}

void dfs(int now, int s)
{
	if(vv[now] && now == s)
	{
		vector::iterator it;
		// in_node[i] records a arc outside the circle whose head is in_node[i] and the val is smallest.
		

		int i;
		int tmp;

		int k;
		int min_arc_in_circle_val = -1;

		int min_entry_cost = INF;
		int min_entry;

		tmp = INF;
		for(it=myvec.begin();it!=myvec.end();++it)
		{
			// Update min_arc_in_circle_val.
			if( cost[nodes[(*it)].pre][(*it)] < tmp )
			{
				tmp = cost[nodes[(*it)].pre][(*it)];
					min_arc_in_circle_val = tmp;
			}

			// Find in_node[i].
			int tmp2 = INF;
			//Set in_node[i] to i;
			in_node[*it] = (*it);
			FORI(int, i, n)
			{
				if ( !vv[i] && cost[i][*it] > 0 && cost[i][*it] < tmp2 )
				{
					in_node[*it] = i;
					tmp2 = cost[i][*it];
				}
			}
		}

		// Find min_entry.
		for(it=myvec.begin();it!=myvec.end();++it)
			if( in_node[*it] != *it )
			{
				tmp = cost[in_node[*it]][*it] - ( cost[nodes[*it].pre][*it] - min_arc_in_circle_val );

				if( tmp < min_entry_cost )
				{
					min_entry_cost = tmp;
					min_entry = *it;
				}
			}

		// Modify min_entry`s father to make a new entry.
		nodes[min_entry].pre = in_node[min_entry];

		return;
	}
	else
	{
		visit[now] = true;
		vv[now] = true;

		// If he has a father.
		if( nodes[now].pre != now )
		{
			myvec.push_back(now);
		
			dfs( nodes[now].pre, s);
			myvec.pop_back();
		}
		
	}
}


你可能感兴趣的:(ACM.图论)