ACM-ICPC 2018 南京賽區網路預賽__L. Magical Girl Haze 【Dijkstra演算法+分層圖思想】

Enjoy_process發表於2018-09-01
  •  1000ms
  •  262144K

There are N cities in the country, and M directional roads from u to v(1≤u,v≤n). Every road has a distance ci​. Haze is a Magical Girl that lives in City 1, she can choose no more than K roads and make their distances become 0. Now she wants to go to City N, please help her calculate the minimum distance.

Input

The first line has one integer T(1≤T≤5), then following T cases.

For each test case, the first line has three integers N,M and K.

Then the following M lines each line has three integers, describe a road, Ui​,Vi​,Ci​. There might be multiple edges between u and v.

It is guaranteed that N≤100000,M≤200000,K≤10,
0 ≤Ci​≤1e9. There is at least one path between City 1 and City N.

Output

For each test case, print the minimum distance.

樣例輸入

1
5 6 1
1 2 2
1 3 4
2 4 3
3 4 1
3 5 6
4 5 2

樣例輸出

3

題目來源

ACM-ICPC 2018 南京賽區網路預賽

題目大意:有N個城市,M條有向邊,城市之間可能有多條邊,你可以選擇讓至多K條邊的長度變為0,問最好的情況下,城市1到城市N的最短路徑為多少

題解:Dijkstra演算法+分層圖思想,具體看程式碼來理解分層圖思想

AC的C++程式碼:

#include<iostream>
#include<vector>
#include<queue>
#include<cstring> 

using namespace std;

typedef long long ll;

const int INF=0x3f3f3f3f;
const int N=100003;

struct Edge{//邊 
	int v,w;//起點到終點v的花費為w 
	Edge(int v,int w):v(v),w(w){} 
};

struct Node{
	int u;
	int w;
	Node(){}
	Node(int u,int w):u(u),w(w){}
	bool operator<(const Node &a)const//使用優先佇列,故將<過載為大於含義 
	{
		return w>a.w;
	}
};

vector<Edge>g[N];
ll dist[N][11];//dist[i][j]表示在使得j條邊為0的情況下源點到結點i的最短路 
bool vis[N][11];

void dijkstra(int s,int n,int k)//源點為s,共有n個結點 可以選擇k條邊為0 
{
	priority_queue<Node>q;
	memset(vis,false,sizeof(vis));
	memset(dist,INF,sizeof(dist));
	dist[s][0]=0;
	q.push(Node(s,0));
	while(!q.empty()){
		Node e=q.top();
		q.pop();
		
		int z=e.u/(n+1);//z表示使z條邊的長度為0 
		int u=e.u%(n+1);//u表示當前結點編號 
		 
		if(!vis[u][z]){//如果還未用dist[u][z]更新其他狀態就進行更新 
			vis[u][z]=true;
			int num=g[u].size();//與u相連的點有num個 
			for(int i=0;i<num;i++){
				int v=g[u][i].v;//v為與u相連的點
				if(vis[v][z])//如果dist[u][z]已經得到了就跳過 
				   continue;
				int c=g[u][i].w;//c表示結點u到結點v的距離 
				//選擇1:不讓這條邊為0
				if(dist[v][z]>dist[u][z]+c){ 
					dist[v][z]=dist[u][z]+c;
	/*第一個引數 z*(n+1)+v是為了使得z可以通過e.u/(n+1)得到,u可以 
	通過e.u%(n+1)得到 */ 
					q.push(Node(z*(n+1)+v,dist[v][z]));
				}
				if(z==k)//如果已經使k條邊為0,就跳過 
				  continue;
				//選擇2:讓這條邊為0,則dist[v][z]變為dist[v][z+1]因為多讓一條邊變為0 
				if(dist[v][z+1]>dist[u][z]){ 
					dist[v][z+1]=dist[u][z];
					q.push(Node((z+1)*(n+1)+v,dist[v][z+1]));
				}
			}
		}
	}
}

int main()
{
	int t,n,m,a,b,k,c;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&n,&m,&k);
		for(int i=0;i<=n;i++)
		  g[i].clear();
	    while(m--){
		  scanf("%d%d%d",&a,&b,&c);
		  g[a].push_back(Edge(b,c));
	    }
	    dijkstra(1,n,k);
	    printf("%lld\n",dist[n][k]);
	   }
	return 0;
} 

 

相關文章