bzoj1097

最短路+状压dp

肯定是状压dp

那么我们把k个点的单源最短路预处理出来,然后dp[i][j]表示状态为i,当前在j需要走的最短距离,给定的限制用状态压一下就行了

注意特判k=0的情况

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int N = 20010, D = 20;
struct edge {
    int nxt, to, w;
} e[N * 20];
int n, m, k, cnt = 1, ans = 0x3f3f3f3f, L;
int head[N], dp[1 << D][D], d[D][N], id[D], can[D];
inline void read(int &x)
{
    x = 0;
    int f = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
    while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + c - '0'; c = getchar(); }
    x *= f;
}
void link(int u, int v, int w)
{
    e[++cnt].nxt = head[u];
    head[u] = cnt;
    e[cnt].to = v;
    e[cnt].w = w;
}
void dijkstra(int s, int *d)
{
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
    d[s] = 0;
    q.push(make_pair(0, s));
    while(!q.empty())
    {
        pair<int, int> o = q.top();
        q.pop();
        int u = o.second;
        if(d[u] < o.first) continue;
        for(int i = head[u]; i; i = e[i].nxt) if(d[e[i].to] > d[u] + e[i].w)
        {
            d[e[i].to] = d[u] + e[i].w;
            q.push(make_pair(d[e[i].to], e[i].to));
        }
    }
}
int main()
{
//  freopen("travel.in", "r", stdin);
//  freopen("travel.out", "w", stdout);
    read(n);
    read(m);
    read(k);
    for(int i = 1; i <= m; ++i)
    {
        int u, v, w;
        read(u);
        read(v);
        read(w);
        link(u, v, w);
        link(v, u, w);
    }
    memset(d, 0x3f3f, sizeof(d));
    read(L);
    for(int i = 0; i < k; ++i) id[i] = i + 2, dijkstra(id[i], d[i]);
    for(int i = 1; i <= L; ++i) 
    {
        int u, v;
        read(u);
        read(v);
        can[v - 2] |= (1 << (u - 2));
    }
    if(k == 0) 
    {
        dijkstra(1, d[0]);
        printf("%d\n", d[0][n]);
        return 0;
    }
    memset(dp, 0x3f3f, sizeof(dp));
    for(int i = 0; i < k; ++i) if(!can[i]) dp[1 << i][i] = d[i][1];
    for(int i = 0; i < (1 << k); ++i)
        for(int j = 0; j < k; ++j) if(i & (1 << j))
            for(int x = 0; x < k; ++x) if(!(i & (1 << x)) && ((i & can[x]) == can[x]))
                dp[i ^ (1 << x)][x] = min(dp[i ^ (1 << x)][x], dp[i][j] + d[j][id[x]]);
    for(int i = 0; i < k; ++i) ans = min(ans, dp[(1 << k) - 1][i] + d[i][n]);
    printf("%d\n", ans);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}
View Code

 

posted @ 2017-10-18 20:32  19992147  阅读(224)  评论(0编辑  收藏  举报