USACO Sweet Butter 解题报告

刚开始用Floyd Warshall算法求每对节点的最短路径,时间复杂度为v^3,空间上用的是邻接矩阵,结果超时。总结:这种方法适合于密集图。

后来考虑用dijsktra算法求单源最短路径,但是heap实现起来比较复杂,还得多个时间复杂度为O(logn)的decreasemin方法。网上看解题报告,看到了Shortest_Path_Faster_Algorithm。于是去wikipedia(http://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm)上查看。思路很简单,据称最坏时间复杂 度非常坏,但在稀疏图中的时间复杂度好,为O(E),并且可以应用在(无负环)的负数权值图中。于是照着伪代码实现了。效果非常好。之后照着wikipedia后面介绍的优化方法写了下,也很简单,也有时间上的提升。

TASK: butter
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 5868 KB]
   Test 2: TEST OK [0.000 secs, 5868 KB]
   Test 3: TEST OK [0.000 secs, 5868 KB]
   Test 4: TEST OK [0.000 secs, 5868 KB]
   Test 5: TEST OK [0.000 secs, 5868 KB]
   Test 6: TEST OK [0.000 secs, 5868 KB]
   Test 7: TEST OK [0.011 secs, 5868 KB]
   Test 8: TEST OK [0.022 secs, 5868 KB]
   Test 9: TEST OK [0.043 secs, 5868 KB]
   Test 10: TEST OK [0.043 secs, 5868 KB]

All tests OK.
附注:一块草地上可以有不止一头牛。

代码如下:

/*
ID: thestor1
LANG: C++
TASK: butter
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <algorithm>
#include <stack>
#include <set>
#include <queue>

using namespace std;

const int P = 800;
const int infinity = 180000;

int dis[P][P];

struct Edge{
	int v;
	int w;
	Edge *next;
	Edge(int v, int w)
	{
		this->v = v;
		this->w = w;
		this->next = NULL;
	}
};

struct Vertex{
	int u;
	Edge *adj;
	Vertex(int i)
	{
		this->u = i;
		adj = NULL;
	}
};

void spfa(const int s, const int p, Vertex **vertexes)
{
	for(int i = 0; i < p; ++i)
	{
		dis[s][i] = infinity;
	}
	dis[s][s] = 0;

	deque<int> que;
	bool onQueue[P];
	memset(onQueue, false, p * sizeof(bool));

	que.push_back(s);
	onQueue[s] = true;

	while(!que.empty())
	{
		int u = que.front();
		que.pop_front();
		onQueue[u] = false;
		for(Edge *e = vertexes[u]->adj; e != NULL; e = e->next)
		{
			if(dis[s][u] + e->w < dis[s][e->v])
			{
				dis[s][e->v] = dis[s][u] + e->w;
				if(!onQueue[e->v])
				{
					if(que.empty() || dis[s][e->v] < dis[s][que.front()])
					{
						que.push_front(e->v);
					}
					else
					{
						que.push_back(e->v);
					}
					onQueue[e->v] = true;
				}
			}
		}
	}
}

int main()
{
	FILE *fin  = fopen ("butter.in", "r");
	FILE *fout = fopen ("butter.out", "w");
	//freopen("log_1.txt", "w", stdout);

	int n, p, c;
	fscanf(fin, "%d%d%d", &n, &p, &c);

	Vertex **vertexes = new Vertex*[p];
	for(int i = 0; i < p; ++i)
	{
		vertexes[i] = new Vertex(i);
	}

	vector<int> dests;
	for(int i = 0; i < n; ++i)
	{
		int dest;
		fscanf(fin, "%d", &dest);
		dests.push_back(dest - 1);
	}

	for(int i = 0; i < c; ++i)
	{
		int p1, p2, d;
		fscanf(fin, "%d%d%d", &p1, &p2, &d);

		Edge *euv = new Edge(p2 - 1, d);
		euv->next = vertexes[p1 - 1]->adj;
		vertexes[p1 - 1]->adj = euv;

		Edge *evu = new Edge(p1 - 1, d);
		evu->next = vertexes[p2 - 1]->adj;
		vertexes[p2 - 1]->adj = evu;
	}

	for(int i = 0; i < n; ++i)
	{
		spfa(dests[i], p, vertexes);
	}

	int mindis = -1;
	for(int i = 0; i < p; ++i)
	{
		int sum = 0;
		for(int j = 0; j < n; ++j)
		{
			sum += dis[dests[j]][i];
			//fprintf(stdout, "%d->%d: %d, ", i, dests[j], dis[dests[j]][i]);
		}
		//fprintf(stdout, "\n%d: %d\n\n", i, sum);
		if(mindis < 0 || sum < mindis)
		{
			mindis = sum;
		}
	}

	fprintf(fout, "%d\n", mindis);

	return 0;
}


你可能感兴趣的:(USACO Sweet Butter 解题报告)