首页 > 其他 > 详细

20180219膜你赛题解

时间:2019-02-22 19:40:48      阅读:183      评论:0      收藏:0      [点我收藏+]

介于本场比赛题目难度并不按照难度顺序排列,所以题解顺序不同。

需要题面或数据可以私聊我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膜你赛题解

原文:https://www.cnblogs.com/ckn1023/p/10420195.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!