1. 程式人生 > >ACM-ICPC 2018 南京賽區網路預賽 L. Magical Girl Haze(dijkstra+分層最短路)

ACM-ICPC 2018 南京賽區網路預賽 L. Magical Girl Haze(dijkstra+分層最短路)

思路來源

https://blog.csdn.net/zhangche0526/article/details/62881066

題意

給你n個城市,m條邊,

共有k次免費機會,可以將其中k條邊的權值變為0,

求點1到點n的最短路。

題解

(百度 分層圖最短路問題 發現是原題 QAQ)

首先,感謝思路來源的答主,

畫了個圖,讓我懂了這題的原理,

本來看了好幾篇都不懂的 QAQ

 

建(k+1)層圖,依次對應第0層,第1層,…,第k層,

每層內部,對應原來的圖;層與層之間,建權值為0的邊,

即我們在建圖的時候,

層內,仍然是u->v的關係,權值為w,

層間,也是u->v的關係,但權值是0,

這代表,可以用一次機會,實現i層向(i+1)層的跨層。

至於這一次用在哪裡,無需深究。

 

第i層,代表已用了i次免費機會,

顯然,免費機會,不用白不用,

所以第k層的終點,就是最優解,

第0層的源點,到第k層的終點,就是最短路

心得

我們共新建了k層圖,包括初始圖共(k+1)層圖,

每層的點是N個,共N*(k+1)個點,

故,點開110W即可。

(k+1)層圖,共(k+1)*m條邊,

每兩層之間,有下層u依照原圖連向上層v的全0邊共m條,共k*m條邊,

總計(2*k+1)*m條邊。

故,邊開420W即可。

偶槽 這竟然是原題是原題是原題啊 BZOJtql

程式碼

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10; 
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<ll,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int n,m,k,head[2000005],cnt;
ll dis[2000005],ans;
bool vis[2000005];
struct edge{int to,nex;ll w;}e[8000005];
priority_queue<pii,vector<pii>,greater<pii> >q;
void init()
{
	for(int i=0;i<2000003;++i)
	dis[i]=8e18;
	ans=8e18;
	cnt=0;
	mem(head,-1);
	mem(vis,0);
}
void add(int u,int v,ll w)
{
	e[cnt].to=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt++;
}
void dijkstra(int u)
{
	while(!q.empty())q.pop(); 
	for(int j=head[u];~j;j=e[j].nex)
	{
		int v=e[j].to;
		ll w=e[j].w;
		dis[v]=w;
		q.push(pii(dis[v],v));
		//printf("v:%d %lf\n",v,dis[v]);
	}
	dis[u]=0;vis[u]=1;
	while(!q.empty())
	{
		pii tmp=q.top();
		q.pop();
		int pos=tmp.second;
		ll d=tmp.first;
		//printf("pos:%d\n",pos); 
		if(vis[pos])continue;
		vis[pos]=1;
		for(int i=head[pos];~i;i=e[i].nex)
		{
			int v=e[i].to;
			ll w=e[i].w;
		    if(dis[v]>dis[pos]+w)
		    {
		    dis[v]=dis[pos]+w;
		    q.push(pii(dis[v],v));
		    }
		}
    }
}
int main()
{ 
    int t;
	sci(t);
	while(t--)
	{
		scanf("%d%d%d",&n,&m,&k);
		init();
		int u,v;
		ll w;
		for(int j=1;j<=m;++j)
		{
		scanf("%d%d%lld",&u,&v,&w);
		u--;v--;
		for(int i=0;i<=k;++i)
		{
			add(u+i*n,v+i*n,w);
			if(i-k)//這一層還有上層 
			{
				add(u+i*n,v+(i+1)*n,0);
			} 
		}
	    }
		dijkstra(0);
		for(int i=0;i<=k;i++)
		ans=min(ans,dis[n-1+i*n]);
		printf("%lld\n",ans);
	} 
	return 0;
}