BZOJ 1579 Revamping Trails

题目链接http://www.zybbs.org/JudgeOnline/problem.php?id=1579

某小朋友给的题,无奈不会做。T T。后来一问知道是用动态规划,搜了下,感觉好神奇。

两种方法,一种是建立层次图,然后求最短路即可。(这个层次图特点是,把所有可能路径(包括任何一条边为0,感觉好神奇)都覆盖掉),见http://hi.baidu.com/lrc2222/blog/item/e40177f76c37b338720eecc7.html

第二种方法就是动态规划了,不过这个动归和本层的有关系,开始很郁闷,想着,难道要用搜索么。。。后来看人家说的,大悟,可以用最短路dijkstra的思想,不断找最小的点去更新还没有被赋值的点。用普通的DIJKSTRA超时了,换成加优先队列的A掉。见http://hi.baidu.com/lxxstar1226/blog/item/0c850ddc5eba4f1e62279875.html

顺便好好学习了下以前对优先队列的误区。。。T T。。。以前一直不会写那个如果只有int的比较函数怎么写。。

#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>

using namespace std;

const int MAX = 10010;
struct NODE{int to,len;NODE *next;};
NODE *p[MAX],node[MAX*10];
int cou;
int dis[25][MAX],L;
void init()
{
	cou = 0;
	memset(node,'\0',sizeof(node));
	memset(p,'\0',sizeof(p));
}
void Add(int x,int y,int w)
{
	node[cou].len = w;
	node[cou].to = y;
	node[cou].next = p[x];
	p[x] = &node[cou++];
}
struct cmp{
	bool operator()(int a,int b)
	{
		return dis[L][a] > dis[L][b];
	}
};
void Dijkstra(int s,int n,int *dis)
{
	bool used[MAX];
	memset(used,0,sizeof(used));
	used[s] = true;
	dis[s] = 0; int now = s;
	for(int i=0; i<n-1; i++)
	{
		NODE *head = p[now];
		while( head )
		{
			if( dis[head->to] > dis[now] + head->len )
				dis[head->to] = dis[now] + head->len;
			head = head->next;
		}
		int mmin = INT_MAX;
		for(int k=1; k<=n; k++)
			if( !used[k] && mmin > dis[k] )
				mmin = dis[now = k];
		used[now] = true;
	}
}
void Dijkstra1(int s,int n,int l)
{
	priority_queue<int,vector<int>,cmp> q;
	bool used[MAX];
	memset(used,0,sizeof(used));
	used[s] = true;
	int now = s;
	dis[l][s] = 0;
	q.push(s);
	while( !q.empty() )
	{
		int now = q.top(); used[now] = true;
		NODE *head = p[now]; q.pop();
		while( head )
		{
			if( dis[l][head->to] > min( dis[l-1][now],dis[l][now] + head->len ) )
			{
				dis[l][head->to] = min( dis[l-1][now],dis[l][now] + head->len );
				q.push(head->to);
			}
			head = head->next;
		}
	}
}

int main()
{
	int n,m,K,x,y,w;
	
	while( ~scanf("%d%d%d",&n,&m,&K) )
	{
		while( m-- )
		{
			scanf("%d%d%d",&x,&y,&w);
			Add(x,y,w); Add(y,x,w);
		}
		for(int k=0; k<=K; k++)
			for(int i=1; i<=n; i++)
				dis[k][i] = 500000000;
		Dijkstra(1,n,dis[0]);
		
		for(L=1; L<=K; L++)
			Dijkstra1(1,n,L);
		printf("%d\n",dis[K][n]);
	}

return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值