1. 程式人生 > >20180219膜你賽題解

20180219膜你賽題解

std 數據 題目 print priority log ons getchar() getc

介於本場比賽題目難度並不按照難度順序排列,所以題解順序不同。

需要題面或數據可以私聊我QQ(不一定在):468170499.

T3:最短路(path)

Describe:

給定一個n個點m條邊的有向圖,有k個標記點,要求從規定的起點按任意順序經過所有標記點到達規定的終點,問最短的距離是多少。

Hint:

20%的數據n<=10。

50%的數據n<=1000。

另有20%的數據k=0。

100%的數據n<=50000,m<=100000,0<=k<=10,1<=z<=5000。

解題思路:

我在考場上寫這道題的時候,一眼沒看出來。在最後看了一眼數據,發現k<=10,那麽答案就非常顯然了。我們可以把標記點為起點跑一邊最短路。我感覺可能會卡SPFA(然而出題人很涼心),所以就寫了一個堆優化的Dijkstra。時間復雜度為O(log(N + M) * N * K)(我習慣變量用小寫)。因為k很小,所以我們可以枚舉所有的方案,再跑一層k的循環判斷。時間復雜度為(K! * K),勉強不會超時,可以寫狀態壓縮優化成O(2^K * K),因為這道題暴力能過,所以就沒寫。這道題我在考場上是只過了一個樣例,之後九分。主要是沒看清題,有向圖連了無向邊。還有dis數組因為不能開到n方的大小,所有有一維應該要存點的編號,然後我在這裏好像弄錯了一點什麽。。。

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 50500, M = 202000, K = 11;
int n, m, k, s, t;
int tot = 0, Link[M], Next[M], to[M];
ll w[M];

inline int read() {
    int num = 0; bool flag = 1; char c = getchar();
    for (; c < 0 || c > 9; c = getchar())
        
if (c == -) flag = 0; for (; c >= 0 && c <= 9; c = getchar()) num = (num << 3) + (num << 1) + c - 48; return flag ? num : -num; } inline ll readll() { ll num = 0; bool flag = 1; char c = getchar(); for (; c < 0 || c > 9; c = getchar())
if (c == -) flag = 0; for (; c >= 0 && c <= 9; c = getchar()) num = (num << 3) + (num << 1) + c - 48; return flag ? num : -num; } inline void add(int x, int y, ll z) { Next[++ tot] = Link[x]; Link[x] = tot; to[tot] = y; w[tot] = z; } // dis[i][j]表示從point[i]號節點為起點到j的最短距離 ll minn = LLONG_MAX; int ans[N], point[N]; bool use[K]; ll dis[K][N]; bool vis[K][N]; void dij(int start) { priority_queue < pair < ll, int> > q; for (int i = 1; i <= n; ++ i) dis[start][i] = 1e15, vis[start][i] = 0; dis[start][point[start]] = 0; q.push(make_pair(0, point[start])); for(; q.size(); ) { int x = q.top().second; q.pop(); if (vis[start][x]) continue; vis[start][x] = 1; for(int i = Link[x]; i; i = Next[i]) { int y = to[i], z = w[i]; if (dis[start][y] > dis[start][x] + z) { dis[start][y] = dis[start][x] + z; q.push(make_pair(-dis[start][y], y)); } } } } void dfs(int depth) { if (depth == k + 1) { ll sum = 0; sum += dis[0][point[ans[1]]]; for (int i = 1; i < k; ++ i) sum += dis[ans[i]][point[ans[i + 1]]]; sum += dis[ans[k]][t]; minn = min(minn, sum); } for (int i = 1; i <= k; ++ i) if (!use[i]) { use[i] = 1; ans[depth] = i; dfs(depth + 1); use[i] = 0; } } int main() { freopen("path.in", "r", stdin); freopen("path.out", "w", stdout); n = read(), m = read(), k = read(), s = read(), t = read(); for (int i = 1; i <= m; ++ i) { int x = read(), y = read(); ll z = readll(); add(x, y, z); } point[0] = s; dij(0); for (int i = 1; i <= k; ++ i) { int sign = read(); point[i] = sign; dij(i); } dfs(1); if (minn == 1e15) puts("-1"); else printf("%lld\n", minn); return 0; }

20180219膜你賽題解