首页 > 代码库 > poj 3662 Telephone Lines spfa算法的灵活运用

poj 3662 Telephone Lines spfa算法的灵活运用

题意:

给一个有n个结点的无向图,要求一条从1到n的路径,你可以让其中的k条免费,这条路径的花费是这条路径上剩下的边中长度的最大值,现在要求花费的最小值。

思路:

这道题可以首先想到二分枚举路径上的最大值,我觉得用spfa更简洁一些。spfa的本质是一种搜索算法,既然是搜索,就涉及到状态的转移。在一般求最短路的spfa算法中,当到结点u时,对e(u,v)只需做如下转移:if(d[v]>d[u]+w(e)) d[v]=d[u]+w(e)。在跟一般的情况下,到结点u,对e(u,v)需做多种转移,比如这题中要考虑让e免费和不让e免费两种情况,具体的请参考实现。

代码:

//poj 3662
//sepNINE
#include <iostream>
#include <queue>
using namespace std;
const int maxN=1024;
const int maxM=10024;

struct Edge
{
	int v,w,next;
}edge[maxM*2];

struct Node
{
	int u,used;	
};
int n,p,k,e;
int head[maxN],dis[maxN][maxN],vis[maxN][maxN];

void spfa(int s,int t,int k)
{
	queue<Node> Q;
	memset(vis,0,sizeof(vis));
	int i,j;
	for(i=1;i<=n;++i)
		for(j=0;j<=k;++j)
			dis[i][j]=INT_MAX;	
	Node x;
	x.u=s;
	x.used=0;
	dis[s][0]=0;
	vis[s][0]=1;
	Q.push(x);
	while(!Q.empty()){
		Node x=Q.front();
		int u=x.u,used=x.used;
		Q.pop();
		vis[u][used]=0;	
		for(int i=head[u];i!=-1;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(used+1<=k&&dis[v][used+1]>dis[u][used]){//让这条边免费,免费的边数used要+1
				dis[v][used+1]=dis[u][used];
				if(vis[v][used+1]==0){
					Node x;
					x.u=v;x.used=used+1;
					vis[x.u][x.used]=1;
					Q.push(x);					
				}
			} 
			if(dis[v][used]>max(dis[u][used],w)){//不让这条边免费,dis[v][used]为dis[u][used]和w中的最大值
				dis[v][used]=max(dis[u][used],w);
				if(vis[v][used]==0){
					Node x;
					x.u=v;x.used=used;
					vis[x.u][x.used]=1;
					Q.push(x);
				}
			}
		}
		
	}
	return ;
}

int main()
{
	scanf("%d%d%d",&n,&p,&k);
	e=0;
	memset(head,-1,sizeof(head)); 
	while(p--){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		edge[e].v=b;edge[e].w=c,edge[e].next=head[a];head[a]=e++;
		edge[e].v=a;edge[e].w=c;edge[e].next=head[b];head[b]=e++;
	}
	spfa(1,n,k);
	int ans=INT_MAX;
	for(int i=0;i<=k;++i)
		ans=min(ans,dis[n][i]);
	if(ans==INT_MAX)
		printf("-1");
	else
		printf("%d",ans);	
	return 0;	
} 


poj 3662 Telephone Lines spfa算法的灵活运用