行动!行动!--SPFA

版权声明:转载请附上地址 https://blog.csdn.net/weixin_44574520/article/details/87556935

行动!行动!

Description
 大CX国的大兵Jack接到一项任务:敌方占领了n座城市(编号0~n-1),有些城市之间有双向道路相连。Jack需要空降在一个城市S,并徒步沿那些道路移动到T城市。虽然Jack每从一个城市到另一个城市都会受伤流血,但大CX国毕竟有着“过硬”的军事实力,它不仅已经算出Jack在每条道路上会损失的血量,还给Jack提供了k个“简易急救包”,一个包可以让Jack在一条路上的流血量为0。Jack想知道自己最少会流多少血,不过他毕竟是无脑的大兵,需要你的帮助。
 Input
 第一行有三个整数n,m,k,分别表示城市数,道路数和急救包个数。
 第二行有两个整数,S,T。分别表示Jack空降到的城市编号和最终要到的城市。
 接下来有m行,每行三个整数a,b,c,表示城市a与城市b之间有一条双向道路。
 Output
 Jack最少要流的血量。
 Sample Input
 5 6 1
 0 3
 3 4 5
 0 1 5
 0 2 100
 1 2 5
 2 4 5
 2 4 3
 Sample Output
 8
 HINT
 【说明】
 对于100%的数据,2<=n<=10000,1<=m<=50000,0<=k<=10.
 

9组为8*1000的网格针对数据,不加优化的spfa只能得10分。
 

附:优先队列语法参考:
 
struct node{
     int dis,pos;
     node():dis(0),pos(0){}//无参初始化
     node(int a,int b):dis(a),pos(b){}//带参初始化
     bool operator <(node x)const    //重载小于运算,用于把priority_queue变成小根堆
     {
         return dis>x.dis;
     }
 };
  
 然后在主模块中这样操作:
 
    priority_queue<node> q;
     q.push(node(x,0));
    node cur=q.top();
    q.pop();
    q.push(cur);

题目分析:

定义d[i][j],表示起点到i号点用了j个包的最短距离;每次spfa判断时分用包和不用包讨论

Code:

#include <bits/stdc++.h>
using namespace std;
#define maxn 100100
#define maxm 500100

int n,m,k,s,t,size=0,head[maxm],vis[maxn][15],d[maxn][15];
struct node{
	int v,w,next;
}e[maxm];

struct cmp{
	int v,bk;
	bool operator < (const cmp &aa) const
	{
		return d[v][0] > d[aa.v][0];
	}
};

inline int read_(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
} 

inline void clean_(){
	memset(d,0x3f,sizeof(d));
	memset(head,-1,sizeof(head));
	memset(vis,0,sizeof(vis));
}

inline void add_(int u,int v,int w){
	e[size].v=v;
	e[size].w=w;
	e[size].next=head[u];
	head[u]=size++;
}

inline void spfa_(){
	priority_queue<cmp> q;
	for(int i=0;i<=k;i++) d[s][i]=0;
	q.push((cmp){s,0});
	vis[s][0]=1;
	while(!q.empty()){
		cmp pp=q.top();
		int x=pp.v;
		int bk=pp.bk;
		q.pop();
		vis[x][bk]=0;
		for(int i=head[x];~i;i=e[i].next){
			int v=e[i].v,w=e[i].w;
			if(d[v][bk]>d[x][bk]+w){//不用包
				d[v][bk]=d[x][bk]+w;
				if(!vis[v][bk]){
					q.push((cmp){v,bk} );
					vis[v][bk]=1;
				}
			}
			if(bk<k&&d[v][bk+1]>d[x][bk]){//用包
				d[v][bk+1]=d[x][bk];
				if(!vis[v][bk+1]){
					q.push((cmp){v,bk+1});
					vis[v][bk+1]=1;
				}
			}
		}
	}
}

inline void init_(){
	freopen("xdong.txt","r",stdin);
}

inline void readda_(){
	clean_();
	n=read_();m=read_();k=read_();
	s=read_();t=read_();
	int a,b,z;
	for(int i=0;i<m;i++){
		a=read_();b=read_();z=read_();
		add_(a,b,z);add_(b,a,z);
	} 
}

inline void work_(){
	int ans=99999999;
	spfa_();
	for(int i=0;i<=k;i++) ans=min(ans,d[t][i]);
	printf("%d",ans);
}

int main(){
	init_();
	readda_();
	work_();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44574520/article/details/87556935