sgu145:Strange People

题意很简单,就是要求第k短路。

看网上好多人都是用dfs+二分过的,我果断作死写了个dijstra+A*。

但最坑的是这道题竟然标程都PE,估计sgu数据坑...

代码正确性应该还是有的,还是贴贴吧。

<pre name="code" class="cpp">#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 105, INF = 1e9;
int n = 0, m = 0, k = 0, s = 0, e = 0;
int mtx[MAXN][MAXN] = {0};
struct node{int x, g, h, pd[4];};
int dis[MAXN] = {0};
bool used[MAXN] = {0};
int ans = 0, time[MAXN] = {0};

bool operator < (const node &A, const node &B)
{
	if((A.g+A.h) == (B.g+B.h)) return A.g > B.g;
	else return (A.g+A.h) > (B.g+B.h);	
}	

void dijstra()
{
	for(int i = 1; i <= n; ++i)
		dis[i] = INF;
	dis[e] = 0;
	int cur = e;
	for(int i = 1; i <= n; ++i)
	{
		used[cur] = true;
		for(int j = 1; j <= n; ++j)
			if(!used[j] && dis[j] > dis[cur]+mtx[cur][j])
				dis[j] = dis[cur]+mtx[cur][j];
		int minv = INF, minf = 0;
		for(int j = 1; j <= n; ++j)
			if(!used[j])
				if(minv > dis[j])
				{
					minv = dis[j];
					minf = j;	
				}
		cur = minf;
	}
}

void A_star()
{
	priority_queue<node> q;	
	node tmp = {s, 0, dis[s], {0}};
	tmp.pd[0] += 1<<(s-1);
	q.push(tmp);
	while(!q.empty())
	{
		node T = q.top();
		q.pop();
		time[T.x]++;
		if(time[T.x] >= k)
		{
			if(T.x == e)
			{
				ans = T.g+T.h;
				printf("%d", ans);
				return ;
			}
			if(time[T.x] > k)
				continue;
		}
		for(int i = 1; i <= n; ++i)
		{
			if(mtx[T.x][i])
			{
				tmp = T;//二进制是为了判断不能走重复的点。
				if(i <= 30)
				{
					if(T.pd[0]&(1<<(i-1)))
						continue;
					else tmp.pd[0] += 1<<(i-1);
				}
				else if(i > 30 && i <= 60)
				{
					if(T.pd[1]&(1<<(i-31)))
						continue;
					else tmp.pd[1] += 1<<(i-31);
				}
				else if(i > 60 && i <= 90)
				{
					if(T.pd[2]&(1<<(i-61)))
						continue;
					else tmp.pd[2] += 1<<(i-61);
				}
				else 
				{
					if(T.pd[3]&(1<<(i-91)))
						continue;
					else tmp.pd[3] += 1<<(i-91);	
				}
				tmp.x = i;
				tmp.g = T.g+mtx[T.x][i];
				tmp.h = dis[i];
				q.push(tmp);
			}
		}
	}
}

int path[MAXN] = {0}, top = 0;
bool flag = false;
void dfs(int cur, int d)
{
	if(d > ans || flag) return ;
	path[++top] = cur;
	used[cur] = true;
	if(cur == e && d == ans)	
	{
		printf(" %d\n", top);
		if(top >= 1)	
			printf("%d", path[1]);
		for(int i = 2; i <= top; ++i)	
			printf(" %d", path[i]);
		flag = true;
		return ;
	}
	for(int i = 1; i <= n; ++i)
		if(!used[i] && mtx[cur][i])	
			dfs(i, d+mtx[cur][i]);
	path[top--] = 0;
	used[cur] = false;
}

int main()
{
	scanf("%d%d%d", &n, &m, &k);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			if(i != j) mtx[i][j] = INF;
	for(int i = 1; i <= m; ++i)
	{
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		mtx[x][y] = mtx[y][x] = z;	
	}
	scanf("%d%d", &s, &e);
	if(s == e) k++;
	
	dijstra();
	
	A_star();
	
	memset(used, false, sizeof(used));
	dfs(s, 0);
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值