HDU 3655 Ensure No Absence

/*
题目意思:找出这么一些点x,满足从1,2,3沿着各自的最短路走到x的路途上不可能相遇
1 分别以1,2,3为起点求出1,2,3到各个点的最短路
2 枚举边,到边起点u的最短路为dis1,dis2,sis3,到终点v的最短路为Dis1,Dis2,Dis3
  如果Disx==disx+边权,那么终点v必定不满足条件,筛去
3 找出未筛去并且1,2,3都可达的点  
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include<map>
#include<queue>
#include<ctime>
using namespace std;
typedef long long int64;
const int MAXV=3009;
const int MAXE=500009;
const int INF = 1<< 27;
struct E
{
	int u,v,w;
}e[MAXE];
int num,n,m;
//heap优化的Dijkstra
struct Dijkstra {
	struct Edge {
		Edge *next;
		int to;
		int dis;
	} ep[MAXE];
	Edge* g[MAXV];
	int heap[MAXV], inhp[MAXV];
	int d[MAXV];
	int V;
	int eN, hsize;
	//[0,n)
	inline void init(int n) {
		memset(g, 0, sizeof(g));
		V = n;
		eN = -1;
	}
	void addEdge(int u, int v, int dd) {
		ep[++eN].to = v;
		ep[eN].dis = dd;
		ep[eN].next = g[u];
		g[u] = &ep[eN];
	}
	void sift(int r) {
		int s = r;
		int fa;
		while ((fa = s << 1) <= hsize) {
			int p = fa, q = fa + 1;
			if (q <= hsize && d[heap[q]] < d[heap[p]])
				p = q;
			if (d[heap[p]] < d[heap[s]]) {
				inhp[heap[p]] = s;
				inhp[heap[s]] = p;
				swap(heap[p], heap[s]);
			} else break;
			s = p;
		}
	}
	int extractMin() {
		int res = heap[1];
		inhp[heap[hsize]] = 1;
		heap[1] = heap[hsize--];
		sift(1);
		return res;
	}
	void decreaseKey(int v, int ndis) {
		d[v] = ndis;
		int p = inhp[v];
		int fa;
		while (p > 1 && d[heap[p]] < d[heap[fa = (p >> 1)]]) {
			inhp[heap[p]] = fa;
			inhp[heap[fa]] = p;
			swap(heap[fa], heap[p]);
			p = fa;
		}
	}

	void solve(int source, int sink) {
		static bool ok[MAXV];
		memset(ok,false,sizeof(ok));
		inhp[source] = 1;
		ok[source] = true;
		heap[1] = source;
		hsize = 1;
		for (int i = 0; i < V; i++) d[i] = INF;
		d[source] = 0;
		for (int i = 0; i < V; i++) {
			if (i != source) {
				heap[++hsize] = i;
				inhp[i] = hsize;
			}
		}
		while (hsize > 0) {
			int u = extractMin();
			ok[u] = true;
		//	if (u == sink) return;
			for (Edge* i = g[u]; i; i = i->next) {
				if (!ok[i->to] && i->dis + d[u] < d[i->to]) {
					decreaseKey(i->to, i->dis + d[u]);
				}
			}
		}
	}
} g[3];
int flag[MAXV];
int ans[MAXV];
int main()
{
	int u,v;
	int w;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i=0;i<3;i++)
		g[i].init(n);
		memset(flag,0,sizeof(flag));
		num=0;
		for(int i=0;i<m;i++)
		{
			scanf("%d%d%d",&u,&v,&w);
			u--;v--;
			for(int i=0;i<3;i++)
			{
			g[i].addEdge(u,v,w);
			g[i].addEdge(v,u,w);
			}
			e[num].u=u;//以起、终,权的方式存边,方便后面枚举
			e[num].v=v;
			e[num++].w=w;
			e[num].u=v;
			e[num].v=u;
			e[num++].w=w;
		}
		for(int i=0;i<3;i++)
		g[i].solve(i,n);//步骤1
		int k;
		for(int i=0;i<num;i++)
		{
			k=0;
			u=e[i].u,v=e[i].v,w=e[i].w;
			for(int i=0;i<3;i++)
			if(g[i].d[u]+w==g[i].d[v])k++;
			if(k>=2)
			flag[v]=1;
		}//步骤2
		k=0;
		for(int i=0;i<n;i++)
		{
			if(!flag[i]&&g[0].d[i]<INF&&g[1].d[i]<INF&&g[2].d[i]<INF)
			ans[k++]=i;
		}//步骤3
		if(k==0)puts("impossible");
		else if(k>0)
		{
		printf("%d\n",k);
		for(int i=0;i<k-1;i++)
		printf("%d ",ans[i]+1);
		printf("%d\n",ans[k-1]+1);
		}
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值