【图的再构造】 uva 10917

题目大意:一张无向图上面有Jimmy的家和Jimmy的公司。

Jimmy必须要走满足一下条件的路:如果Jimmy要从A走到B,必须存在一条以B为起点的路径,比从任何一条以A为起点的路径短。

 

思路:所谓的“必须存在一条以B为起点的路径,比从任何一条以A为起点的路径短。” 也就是说,从A开始的最短路径比从B开始的最短路径短。 因此跑完一边最短路径后,我们对所有d[x] > d[y]的点对建立一条边。

 

得到的新的图必然是一棵树(想一想,为什么?)

然后跑一边一个很简单的树上dp就可以了。

 

#include <bits/stdc++.h>
#define CLR(arr) memset(arr,0,sizeof(arr))
using namespace std;
const int maxn = 1020;
typedef long long ll;

struct HeapNode{
	int u,d;
	bool operator < (const HeapNode& rhs) const
	{
		return d > rhs.d;	
	} 
};
struct Edge{
	int u,v,dist;
};

int ecnt;
int d[maxn];
int p[maxn];
bool done[maxn];
vector<int> G[maxn];
vector<Edge> edge;

void AddEdge(int u, int v, int dist)
{
	edge.push_back(Edge{u,v,dist});
	G[u].push_back(ecnt++);
}

void dijkstra(int s)
{
	CLR(done);
	memset(d,0x3f,sizeof(d));
	
	d[s] = 0;

	priority_queue<HeapNode> Q;
	Q.push(HeapNode{s,0});
	while(!Q.empty())	
	{
		HeapNode x = Q.top(); Q.pop();
		int u = x.u;
		if(done[u]) continue;
		done[u] = true;
		
		for (int i = 0 ; i < G[u].size() ;++i)
		{
			Edge &e = edge[G[u][i]];
			if(d[e.v] > d[u] + e.dist)
			{
				d[e.v] = d[u] + e.dist;
				p[e.v] = u;	
				Q.push(HeapNode{e.v,d[e.v]});
			} 	
		} 
	}
}

int F[maxn];
vector<int> tree[maxn];
void init(int n){
	CLR(p);
	CLR(F);
	for (int i = 0 ; i < n ; ++i) G[i].clear();
	for (int i = 0 ; i < n ; ++i) tree[i].clear(); 
	edge.clear();
	ecnt = 0;
}



int dp(int k)
{
	if(k == 0) return 1;
	if(F[k] != -1) return F[k];
	int& ret = F[k];
	ret = 0;
	for (int i = 0 ; i < tree[k].size() ; ++i)
	{
		int v = tree[k][i]; 
		ret += dp(v);
	}
	return ret;
}


bool vis[maxn];

int main()
{
	int n,m;
	while(cin >> n )
	{
		if(n==0) break;
		cin >> m;
		int a,b,t;
		init(n);
		for (int i = 0 ; i < m ; ++i)
		{
			cin >> a >> b >> t;
			a--;b--;
			AddEdge(a,b,t);
			AddEdge(b,a,t);
		}

		dijkstra(2-1);
		CLR(vis);

		memset(F,-1,sizeof(F));
		for (int u = 0 ; u < n ; ++u)	
			for (int i = 0 ; i < G[u].size() ; ++i)
			{
				Edge &e = edge[G[u][i]];
				int v = e.v;
				if(d[v] > d[u])
					tree[u].push_back(v);				
			}
		
		int ans = 0;
		ans = dp(1);
		cout << ans << endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值