POJ 1135Domino Effect

题目链接:http://poj.org/problem?id=1135

            就是一个单源最短路问题,从编号为1的骨牌开始,按最短路依次倒下,求最后一个骨牌倒下需要多长时间,当求完最短路后,所有点中的最长时间也不一定是所求结果,我们把所求的最短路放在dis[MAX]数组中,如果编号为 i 的 结点不是出度为零的结点,那么它还要继续倒,我们可以枚举每条边,如果两个相邻结点倒的过程中在路径上相碰,那么相碰那一刻所用的时间就是这条路径的最长时间 t,最大的 t 就是结果,可能说不太清楚,比如i,j两个结点有边,权值为w(i,j),并且i 所得的最短路不是从j点来的,j点也不是从i点来的,这两个结点的骨牌会在i,j这条边上相碰,如果abs(dis[i] - dis[j]) > w(i,j) 就可以直接放弃这个情况了(可以想想为什么,因为这样他们就不会再边上碰了),反之t = (dis[i]+dis[j]+w(i,j)) / 2.0; 枚举完所有边就可求出结果,注意只有一个牌的时候输出0.0,不需要时间。(说不清楚。。。。)参考代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;

#define MAX 505
#define CLR(arr,v) memset(arr,v,sizeof(arr))

struct point
{
	int v,d;
	friend bool operator<(point a,point b)
	{
		return a.d > b.d;
	}
}mid;
int dis[MAX],h[MAX],nex[MAX*MAX],val[MAX*MAX],des[MAX*MAX],pre[MAX],pos;
bool vis[MAX];
priority_queue<point> q;

void init()
{
	pos = 0;
	CLR(pre,0);CLR(vis,0);
	CLR(h,0);  CLR(nex,0);
	CLR(val,0);CLR(des,0);
	fill(dis,dis+MAX,INT_MAX);
	while(!q.empty()) q.pop();
}

void add(int u,int v,int d)
{
	val[++pos] = d;
	des[pos] = v;
	nex[pos] = h[u];
	h[u] = pos;
}

void dijkstra(int n)
{
	dis[1] = 0;
	mid.v = 1;  mid.d = 0;
	pre[1] = 0; q.push(mid);
	for(int i = 0;i < n;++i)
	{
		while( !q.empty() && vis[q.top().v]) q.pop();
		if(q.empty()) break;
		vis[q.top().v] = true;
		int p = q.top().v,d = q.top().d;
		q.pop();
		for(int j = h[p]; j ;j = nex[j])
		{
			if(!vis[ des[j] ] && (dis[ des[j] ] == INT_MAX || dis[p] + val[j] < dis[ des[j] ]))
			{
				dis[ des[j] ] = dis[p] + val[j];
				mid.v = des[j];
				mid.d = dis[ des[j] ];
				q.push(mid);
				pre[ des[j] ] = p;
			}
		}
	}
}

int main()
{
	int m,n,k = 1;
	while(~scanf("%d%d",&n,&m) && m + n)
	{
		init();
		int u,v,d;
		for(int i = 0;i < m;++i)
		{
			scanf("%d%d%d",&u,&v,&d);
			add(u,v,d);
			add(v,u,d);
		}
		dijkstra(n);
		double res = -1;
		int p1,p2;
		for(int i = 1;i <= n;++i)
		{
			if(res < dis[i])
			{
				res = dis[i];
				p1 = p2 = i;
			}
			for(int j = h[i]; j ;j = nex[j])
			{
				if(pre[i] == des[j] || pre[ des[j] ] == i)
					continue;
				if(abs(dis[i] - dis[ des[j] ]) >= val[j])
					continue;
				v = des[j];
				d = val[j];
				double num = (dis[i] + dis[ des[j] ] + d) / 2.0;
				if(res <= num)
				{
					res = num;
					p1 = i < des[j]?i:des[j];
					p2 = i > des[j]?i:des[j];
				}
			}
		}
		printf("System #%d\n",k++);
		printf("The last domino falls after %.1lf seconds, ",res);
		if(p1 == p2) 
			printf("at key domino %d.\n\n",p1);
		else
			printf("between key dominoes %d and %d.\n\n",p1,p2);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值