图论





强连通分量


POJ 2186 popular cow 从一个没有入度的连通分量遍历图

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

int n, m;

vector<vector<int> > g(10010);
vector<vector<int> > rg(10010);

vector<int> order;
int cnt;
int visited[10010];
int color[10010];

void dfs(int v)
{
	visited[v] = 1;
	for (int i = 0; i < g[v].size(); i++)
	{
		if (!visited[g[v][i]])
			dfs(g[v][i]);
	}
	order.push_back(v);
}

void rdfs(int v, int k)
{

	color[v] = k;
	visited[v] = 1;
	for (int i = 0; i < rg[v].size(); i++)
	{

		if (!visited[rg[v][i]])
			rdfs(rg[v][i], k);
	}
}


int main()
{
	scanf("%d%d", &n, &m);

	int a, b;
	for (int i = 0; i < m; i++)
	{
		scanf("%d%d", &a, &b);
		g[a].push_back(b);
		rg[b].push_back(a);
	}



	memset(visited, 0, sizeof(visited));
	for (int i = 1; i <= n; i++)
	{
		if (!visited[i])
			dfs(i);
	}


	cnt = 0;
	memset(visited, 0, sizeof(visited));
	for (int i = order.size() - 1; i >= 0; i--)
	{
		if (!visited[order[i]])
			rdfs(order[i], cnt++);
	}

	int ans = 0;
	int u;
	for (int i = 1; i <= n; i++)
		if (color[i] == cnt - 1)
		{
			ans++;
			u = i;
		}


	memset(visited, 0, sizeof(visited));
	rdfs(u, 0);

	for (int i = 1; i <= n; i++)
		if (visited[i] == 0)
		{
			ans = 0;

			break;
		}

	printf("%d\n", ans);
}





POJ 2186 popular cow 看每个连通分量的入度

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

int n, m;

vector<vector<int> > g(10010);
vector<vector<int> > rg(10010);

vector<int> order;
int cnt;
int visited[10010];
vector<vector<int> > colorSet;
int colorHash[10010];

void dfs(int v)
{
	visited[v] = 1;
	for (int i = 0; i < g[v].size(); i++)
	{
		if (!visited[g[v][i]])
			dfs(g[v][i]);
	}
	order.push_back(v);
}

void rdfs(int v, int k)
{
	colorSet[k].push_back(v);
	colorHash[v] = k;
	visited[v] = 1;
	for (int i = 0; i < rg[v].size(); i++)
	{

		if (!visited[rg[v][i]])
			rdfs(rg[v][i], k);
	}
}


int main()
{
	scanf("%d%d", &n, &m);

	int a, b;
	for (int i = 0; i < m; i++)
	{
		scanf("%d%d", &a, &b);
		g[a].push_back(b);
		rg[b].push_back(a);
	}



	memset(visited, 0, sizeof(visited));
	for (int i = 1; i <= n; i++)
	{
		if (!visited[i])
			dfs(i);
	}


	cnt = 0;

	memset(visited, 0, sizeof(visited));
	for (int i = order.size() - 1; i >= 0; i--)
	{
		if (!visited[order[i]])
		{
			colorSet.push_back(vector<int>());
			rdfs(order[i], cnt++);
		}
	}




	int ans = 0;
	int endPoint = 0;

	for (int i = 0; i < colorSet.size(); i++)//每个连通分支
	{
		int tag = 0;
		for (int j = 0; j < colorSet[i].size(); j++)//每个连通分支的每个点
		{

			int u = colorSet[i][j];


			for (int k = 0; k < g[u].size(); k++)//一个连通分支的一个点的边
			{
				if (colorHash[g[u][k]] != i)
				{
					tag = 1;
					break;
				}

			}
			if (tag == 1)
				break;
		}


		if (tag == 0)
		{
			endPoint++;
			ans = colorSet[i].size();
		}
	}

	if (endPoint != 1)
		ans = 0;

	printf("%d\n", ans);
}




POJ 1236 网络传输

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

int n;

vector<vector<int> > g;
vector<vector<int> > rg;

vector<int> dfsOrder;
int ncolor;
int visited[110];
vector<vector<int> > colorSet;
int colorHash[110];

void dfs(int v)
{
	visited[v] = 1;
	for (int i = 0; i < g[v].size(); i++)
	{
		if (!visited[g[v][i]])
			dfs(g[v][i]);
	}
	dfsOrder.push_back(v);
}

void rdfs(int v, int k)
{
	colorSet[k].push_back(v);
	colorHash[v] = k;
	visited[v] = 1;
	for (int i = 0; i < rg[v].size(); i++)
	{

		if (!visited[rg[v][i]])
			rdfs(rg[v][i], k);
	}
}



int main()
{
	scanf("%d", &n);

	g.resize(n + 1);
	rg.resize(n + 1);

	int u;
	for (int i = 1; i <= n; i++)
	{
		while (scanf("%d", &u) == 1 && u != 0)
		{
			g[i].push_back(u);
			rg[u].push_back(i);
		}
	}



	memset(visited, 0, sizeof(visited));
	for (int i = 1; i <= n; i++)
	{
		if (!visited[i])
			dfs(i);
	}


	ncolor = 0;

	memset(visited, 0, sizeof(visited));
	for (int i = dfsOrder.size() - 1; i >= 0; i--)
	{
		if (!visited[dfsOrder[i]])
		{
			colorSet.push_back(vector<int>());
			rdfs(dfsOrder[i], ncolor++);
		}
	}


	int ans1 = 0;
	int startPoint = 0;
	for (int i = 0; i < colorSet.size(); i++)
	{
		int tag = 1;
		for (int j = 0; j < colorSet[i].size(); j++)
		{
			int u = colorSet[i][j];
			for (int k = 0; k < rg[u].size(); k++)//一个连通分支的一个点的边
			{
				if (colorHash[rg[u][k]] != i)
				{
					tag = 0;
					break;
				}

			}
		}
		if (tag)
			ans1++;
	}





	int ans2 = 0;
	int endPoint = 0;

	for (int i = 0; i < colorSet.size(); i++)//每个连通分支
	{
		int tag = 0;
		for (int j = 0; j < colorSet[i].size(); j++)//每个连通分支的每个点
		{

			int u = colorSet[i][j];


			for (int k = 0; k < g[u].size(); k++)//一个连通分支的一个点的边
			{
				if (colorHash[g[u][k]] != i)
				{
					tag = 1;
					break;
				}

			}
			if (tag == 1)
				break;
		}


		if (tag == 0)
		{
			endPoint++;
		}
	}
	ans2 = max(ans1, endPoint);

	if (ncolor == 1)
	{
		printf("%d\n", ans1);
		printf("%d\n", 0);
	}
	else
	{
		printf("%d\n", ans1);
		printf("%d\n", ans2);
	}
}





tarjan 求割点和桥

#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;
#define MAXN 200
typedef vector<int> Edge;
vector<Edge> G(MAXN);
bool Visited[MAXN];
int dfn[MAXN];
int low[MAXN];
int Father[MAXN]; //DFS树中每个点的父节点
bool isCutVex[MAXN]; //每个点是不是割点
int nTime; //Dfs时间戳
int n, m; //n是点数, m是边数
void Tarjan(int u, int father) //father 是u的父节点
{
	Father[u] = father;
	int i, j, k;
	low[u] = dfn[u] = nTime++;
	for (i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if (!dfn[v])
		{
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
		}
		else if (father != v) //连到父节点的回边不考虑,否则求不出桥
			low[u] = min(low[u], dfn[v]);
	}
}void Count()
{ //计算割点和桥
	int nRootSons = 0; 
	int i;
	Tarjan(1, 0);
	for (i = 2; i <= n; i++)
	{
		int v = Father[i];
		if (v == 1)
			nRootSons++; //DFS树中根节点有几个子树
		else
		{
			if (dfn[v] <= low[i])
				isCutVex[v] = true;
		}
	}
	if (nRootSons > 1)
		isCutVex[1] = true;
	for (i = 1; i <= n; i++)
		if (isCutVex[i])
			cout << i << endl;
	for (i = 1; i <= n; i++)
	{
		int v = Father[i];
		if (v > 0 && dfn[v] < low[i])
			cout << v << "," << i << endl;
	}
}int main()
{
	int u, v;
	int i;
	nTime = 1;
	cin >> n >> m; //n是点数, m是边数
	for (i = 1; i <= m; i++)
	{
		cin >> u >> v; //点编号从1开始
		G[v].push_back(u);
		G[u].push_back(v);
	}
	memset(dfn, 0, sizeof(dfn));
	memset(Father, 0, sizeof(Father));
	memset(isCutVex, 0, sizeof(isCutVex));
	Count();
	return 0;
}



tarjan 求双连通分量

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
#define MAXN 200

vector<vector<int> > G(MAXN);
int dfn[MAXN];
int low[MAXN];
int nTime;
int n, m; //n是点数, m是边数

struct Edge
{
	int u;
	int v;
	Edge()
	{
	}
	Edge(int u_, int v_) :u(u_), v(v_)
	{
	}
};

deque<Edge> Edges;

int nBlockNo = 0;

void Tarjan(int u, int father)
{
	int i, j, k;
	low[u] = dfn[u] = nTime++;
	for (i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if (!dfn[v])
		{ //v没有访问过
		  //树边要入栈
			Edges.push_back(Edge(u, v));
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
			Edge tmp;
			if (dfn[u] <= low[v])
			{
				//从一条边往下走,走完后发现自己是割点,则栈中的边一定全是和自己在一个双连通分量里面
				//根节点总是和其下的某些点在同一个双连通分量里面
				cout << "Block No: " << ++nBlockNo << endl;
				do
				{
					tmp = Edges.back();
					Edges.pop_back();
					cout << tmp.u << "," << tmp.v << endl;
				} while (!(tmp.u == u &&tmp.v == v));
			}
		} // 对应if( ! dfn[v]) {
		else
		{
			if (v != father)
			{//u连到父节点的回边不考虑
				low[u] = min(low[u], dfn[v]);
				if (dfn[u] > dfn[v])
					//连接到祖先的回边要入栈,但是连接到儿子的边,此处肯定已经入过栈了,不能再入栈
					Edges.push_back(Edge(u, v));
			}
		}
	} //对应 for( i = 0;i < G[u].size() ;i ++ ) {
}

int main()
{
	int u, v;
	int i;
	nTime = 1;
	cin >> n >> m; //n是点数, m是边数
	nBlockNo = 0;
	for (i = 1; i <= m; i++)
	{
		cin >> u >> v; //点编号从1开始
		G[v].push_back(u);
		G[u].push_back(v);
	}
	memset(dfn, 0, sizeof(dfn));
	Tarjan(1, 0);
	return 0;
}



POJ 3352 道路重建


#include <vector>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<stack>
using namespace std;
#define MAXN 1010
typedef vector<int> Edge;
vector<Edge> g(MAXN);

int dfn[MAXN];
int low[MAXN];


int nTime; //Dfs时间戳
int n, m; //n是点数, m是边数
int degree[MAXN];

stack<int> s;

int colorHash[MAXN];
int ncolor;


void Tarjan(int u, int father) //father 是u的父节点
{

	int i;
	s.push(u);
	low[u] = dfn[u] = nTime++;
	for (i = 0; i < g[u].size(); i++)
	{
		int v = g[u][i];
		if (!dfn[v])
		{
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
		}
		else if (father != v) //连到父节点的回边不考虑,否则求不出桥
			low[u] = min(low[u], dfn[v]);
	}

	if (dfn[u] == low[u])
	{
		int temp;
		do
		{
			temp = s.top();
			s.pop();
			colorHash[temp] = ncolor;
		} while (!s.empty() && temp != u);
		ncolor++;
	}

}

void Count()
{
	
	Tarjan(1, 0);



	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < g[i].size(); j++)
		{
			int v = g[i][j];
			if (colorHash[i] != colorHash[v])
			{
				degree[colorHash[v]]++;
				degree[colorHash[i]]++;

			}
		}
	}

	int leaf = 0;
	for (int i = 0; i < ncolor; i++)
	{
		if (degree[i] == 2)
			leaf++;
	}


	printf("%d\n", (leaf + 1) / 2);
}

int main()
{
	while (scanf("%d%d", &n, &m) == 2) //n是点数, m是边数
	{
		int u, v;
		nTime = 1;
		memset(dfn, 0, sizeof(dfn));
		memset(degree, 0, sizeof(degree));

		for (int i = 0; i < MAXN; i++)
			g[i].clear();
		for (int i = 1; i <= m; i++)
		{
			scanf("%d%d", &u, &v); //点编号从1开始
			g[v].push_back(u);
			g[u].push_back(v);
		}

		Count();
	}


}



最短路




POJ 3159 糖果Dijkstra

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

struct Edge
{
	int v;
	int w;
	Edge()
	{
	}
	Edge(int _v, int _w) :v(_v), w(_w)
	{
	}
};

bool operator<(const Edge & lhs, const Edge & rhs)
{
	return lhs.w>rhs.w;
}

priority_queue<Edge> pq;
bool isUsed[30010];
vector<vector<Edge> > g;
int n, m;

int main()
{
	scanf("%d%d", &n, &m);
	g.clear();
	g.resize(n + 1);
	memset(isUsed, 0, sizeof(isUsed));
	int a, b, c;
	for (int i = 1; i <= m; i++)
	{
		scanf("%d%d%d", &a, &b, &c);
		g[a].push_back(Edge(b, c));
	}

	Edge e(1, 0);
	pq.push(e);
	while (!pq.empty())
	{
		e = pq.top();
		pq.pop();

		if (isUsed[e.v])
			continue;
		isUsed[e.v] = true;
		if (e.v == n)
		{
			printf("%d\n", e.w);
			return 0;
		}
		for (int i = 0; i<g[e.v].size(); i++)
		{
			if (isUsed[g[e.v][i].v])
				continue;
			pq.push(Edge(g[e.v][i].v, e.w + g[e.v][i].w));
		}

	}
}


POJ 3259 Bellman-Ford 判断有无负权值回路

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

struct Edge
{
	int u;
	int v;
	int w;
	Edge()
	{
	}
	Edge(int _u, int _v, int _w) :u(_u), v(_v), w(_w)
	{
	}
};

vector<Edge> g;
int n, m, w;


bool Bellman_Ford(int v)
{
	vector<int> dist(n + 1);

	for (int i = 1; i <= n; i++)
		dist[i] = INF;

	dist[v] = 0;

	for (int i = 1; i<n; i++)
	{
		int flag=0;
		for (int j = 0; j<g.size(); j++)
		{
			int s = g[j].u;
			int e = g[j].v;

			if (dist[s] + g[j].w<dist[e])
			{
				dist[e] = dist[s] + g[j].w;
				flag=1;
			}
		}
		if(flag==0)
			return false;
	}

	for (int i = 0; i<g.size(); i++)
	{
		int s = g[i].u;
		int e = g[i].v;

		if (dist[s] + g[i].w<dist[e])
			return true;
	}
	return false;
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		g.clear();
		scanf("%d%d%d", &n, &m, &w);
		

		int s, e, t;

		for (int i = 1; i <= m; i++)
		{
			scanf("%d%d%d", &s, &e, &t);
			g.push_back(Edge(s, e, t));
			g.push_back(Edge(e, s, t));
		}
		for (int i = 1; i <= w; i++)
		{
			scanf("%d%d%d", &s, &e, &t);
			g.push_back(Edge(s, e, -t));
		}

		if (Bellman_Ford(1))
			printf("YES\n");
		else
			printf("NO\n");
	}
}












POJ 3259 SPFA 判断有无负权值回路

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

struct Edge
{
	int v;
	int w;
	Edge()
	{
	}
	Edge(int _v, int _w) : v(_v), w(_w)
	{
	}
};

vector<vector<Edge> >g;
int n, m, w;


bool spfa(int v)
{
	vector<int> vDist(n + 1);
	vector<int> updateTimes(n + 1);
	vector<bool> inqueue(n + 1);
	for (int i = 1; i <= n; i++)
	{
		vDist[i] = INF;
		updateTimes[i] = 0;
		inqueue[i] = false;
	}
	vDist[v] = 0;
	queue<int> q;
	q.push(v);
	inqueue[v] = true;

	while (!q.empty())
	{
		int u = q.front();
		q.pop();
		inqueue[u] = false;
		for (int i = 0; i < g[u].size(); i++)
		{
			int v = g[u][i].v;
			if (vDist[v] > vDist[u] + g[u][i].w)
			{
				vDist[v] = vDist[u] + g[u][i].w;
				if (inqueue[v] == false)
				{
					q.push(v);
				}
				++updateTimes[v];
				if (updateTimes[v] >= n)
					return true;
			}
		}

	}
	return false;
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{

		scanf("%d%d%d", &n, &m, &w);
		g.clear();
		g.resize(n + 1);

		int u, v, t;

		for (int i = 1; i <= m; i++)
		{
			scanf("%d%d%d", &u, &v, &t);
			g[u].push_back(Edge(v, t));
			g[v].push_back(Edge(u, t));
		}
		for (int i = 1; i <= w; i++)
		{
			scanf("%d%d%d", &u, &v, &t);
			g[u].push_back(Edge(v, -t));
		}

		if (spfa(1))
			printf("YES\n");
		else
			printf("NO\n");
	}
}




POJ 3660 确定名次 弗洛伊德算法

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

int n, m;
int g[110][110];

int dist[110][110];

int main()
{
	scanf("%d%d", &n, &m);
	int a, b;

	memset(g, 0, sizeof(g));

	for (int i = 0; i < 110; i++)
		for (int j = 0; j < 110; j++)
		{
			dist[i][j] = INF;
		}

	for (int i = 0; i < m; i++)
	{
		scanf("%d%d", &a, &b);
		dist[a][b] = g[a][b] = 1;
	}






	for (int k = 1; k <= n; k++)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j])
				{
					dist[i][j] = dist[i][k] + dist[k][j];
				}
			}
		}
	}

	int ans = 0;

	for (int i = 1; i <= n; i++)
	{
		int cnt = 0;
		for (int j = 1; j <= n; j++)
		{
			if (dist[i][j] != INF || dist[j][i] != INF)
				cnt++;
		}

		if (cnt == n - 1)
			ans++;
	}

	printf("%d\n", ans);
}






最小生成树



POJ 1258 kruskal模板


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

struct Edge
{
	int u, v, w;
	Edge(int _u, int _v, int _w) :u(_u), v(_v), w(_w)
	{
	}
	Edge()
	{
	}

	bool operator<(const Edge & rhs)const
	{
		return w < rhs.w;
	}
};

vector<Edge> g;

vector<int> parent;

int n;

int getParent(int a)
{
	if (parent[a] == a)
		return a;
	return parent[a] = getParent(parent[a]);
}

void merge(int a, int b)
{
	int p1 = getParent(a);
	int p2 = getParent(b);

	if (p1 == p2)
		return;

	parent[p2] = p1;

}

int main()
{
	while (scanf("%d", &n) == 1)
	{
		parent.clear();
		g.clear();

		for (int i = 0; i < n; i++)
			parent.push_back(i);

		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
			{
				int w;
				scanf("%d", &w);
				g.push_back(Edge(i, j, w));
			}

		sort(g.begin(), g.end());

		int done = 0;

		int totalLen = 0;

		for (int i = 0; i < g.size(); i++)
		{
			if (getParent(g[i].u) != getParent(g[i].v))
			{
				merge(g[i].u, g[i].v);
				++done;
				totalLen += g[i].w;


			}
			if (done == n - 1)
				break;
		}
		printf("%d\n", totalLen);
	}
}


POJ 1258 primHeap模板

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

struct Edge
{
	int v, w;
	Edge(int _v = 0, int _w = INF) :v(_v), w(_w)
	{
	}
	bool operator<(const Edge & e)const
	{
		return w > e.w;
	}
};

vector<vector<Edge> > g(110);

int n;

int heapPrim()
{
	Edge xDist;
	priority_queue<Edge> pq;
	vector<int> vDist(n);
	vector<int> vUsed(n);

	int nDoneNum = 0;

	for (int i = 0; i < n; i++)
	{
		vDist[i] = INF;
		vUsed[i] = 0;
	}

	int nTotalW = 0;

	pq.push(Edge(0, 0));

	while (nDoneNum < n && !pq.empty())
	{
		do
		{
			xDist = pq.top();
			pq.pop();
		} while (vUsed[xDist.v] == 1 && !pq.empty());
		if (vUsed[xDist.v] == 0)
		{
			nTotalW += xDist.w;
			vUsed[xDist.v] = 1;
			nDoneNum++;

			for (int i = 0; i < g[xDist.v].size(); i++)
			{
				int k = g[xDist.v][i].v;
				if (vUsed[k] == 0)
				{
					int w = g[xDist.v][i].w;
					if (vDist[i] > w)
					{
						vDist[i] = w;
						pq.push(Edge(k, w));
					}
				}

			}
		}
	}
	if (nDoneNum < n)
		return -1;
	return nTotalW;
}

int main()
{
	while (scanf("%d", &n) == 1)
	{
		for (int i = 0; i < n; i++)
			g[i].clear();
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
			{
				int w;
				scanf("%d", &w);
				g[i].push_back(Edge(j, w));
			}
		printf("%d\n", heapPrim());
	}
}



POJ 2349 村庄连接 double用%f

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

struct Edge
{
	int u, v;
	double w;


	bool operator<(const Edge & rhs)const
	{
		return w < rhs.w;
	}
};

Edge g[1000010];

int parent[550];

int n, t, s;

int getParent(int a)
{
	if (parent[a] == a)
		return a;
	return parent[a] = getParent(parent[a]);
}

void merge(int a, int b)
{
	int p1 = getParent(a);
	int p2 = getParent(b);

	if (p1 == p2)
		return;

	parent[p1] = p2;

}

int x[550], y[550];



double ans[550];

int main()
{


	scanf("%d", &t);

	while (t--)
	{
		scanf("%d%d", &s, &n);



		for (int i = 0; i < n; i++)
			parent[i] = i;

		int ncount = 0;

		for (int i = 0; i < n; i++)
		{
			scanf("%d%d", &x[i], &y[i]);
			for (int j = 0; j < i; j++)
			{
				double dist = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));

				g[ncount].u = i;
				g[ncount].v = j;
				g[ncount].w = dist;
				ncount++;
			}
		}



		sort(g, g + ncount);

		int done = 0;



		for (int i = 0; i < ncount; i++)
		{
			if (getParent(g[i].u) != getParent(g[i].v))
			{
				merge(g[i].u, g[i].v);

				ans[done++] = g[i].w;

				if (done == n - s)
				{
					printf("%.2f\n", g[i].w);
					break;
				}
			}
		}
	}
}




UVA 1494 秦始皇修路


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<queue>
#include<ctype.h>
#include<map>
#include<math.h>
using namespace std;

const int INF = 1 << 30;

struct Edge
{
	int v;
	double w;
	Edge()
	{
	}
	Edge(int _v, double _w) :v(_v), w(_w)
	{
	}
	bool operator<(const Edge & e)const
	{
		return w > e.w;
	}
};

double g[1010][1010];

int n;

double max_val[1010][1010];

int x[1010];
int y[1010];
int p[1010];


double heapPrim()
{
	Edge xDist;
	priority_queue<Edge> pq;
	vector<double> vDist(n);
	vector<int> vUsed(n);
	vector<int> vLast(n);
	int nDoneNum = 0;

	for (int i = 0; i < n; i++)
	{
		vDist[i] = INF;
		vUsed[i] = 0;
		vLast[i] = 0;
	}

	double nTotalW = 0;

	pq.push(Edge(0, 0));

	while (nDoneNum < n && !pq.empty())
	{
		do
		{
			xDist = pq.top();
			pq.pop();
		} while (vUsed[xDist.v] == 1 && !pq.empty());
		if (vUsed[xDist.v] == 0)
		{
			nTotalW += xDist.w;
			vUsed[xDist.v] = 1;
			nDoneNum++;

			max_val[vLast[xDist.v]][xDist.v] = max_val[xDist.v][vLast[xDist.v]] = xDist.w;

			for (int i = 0; i < n; i++)
			{
				if (vUsed[i] == 1 && i != vLast[xDist.v])
				{
					max_val[i][xDist.v] = max_val[xDist.v][i] = max(max_val[i][vLast[xDist.v]], max_val[vLast[xDist.v]][xDist.v]);
				}
			}

			for (int i = 0; i < n; i++)
			{


				if (vUsed[i] == 0)
				{
					double w = g[xDist.v][i];

					if (vDist[i] > w)
					{
						vDist[i] = w;
						vLast[i] = xDist.v;
						pq.push(Edge(i, w));

					}
				}

			}
		}
	}


	if (nDoneNum < n)
		exit(1);
	return nTotalW;
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d", &n);



		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				max_val[i][j] = -INF;


		for (int i = 0; i < n; i++)
		{
			scanf("%d%d%d", &x[i], &y[i], &p[i]);


			for (int j = 0; j < i; j++)
			{
				double dist = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));

				g[i][j] = g[j][i] = dist;
			}
		}

		double totalW = heapPrim();


		double ans = -INF;

		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < i; j++)
			{
				ans = max(ans, (p[i] + p[j]) / (totalW - max_val[i][j]));
			}
		}

		printf("%.2f\n", ans);
	}





}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值