[POI 2007] 旅游景点

[题目链接]

        https://www.lydsy.com/JudgeOnline/problem.php?id=1097

[算法]

         首先,用Dijkstra算法求出2-k+1到每个点的最短路

         然后,我们用f[S][i]表示目前停留城市集合为S,现在在城市i,最短的路径

         状压DP即可

[代码]

         

#include<bits/stdc++.h>
using namespace std;
#define MAXN 20010
#define MAXM 200010
#define MAXK 25
const int INF = 2e9;
const int MAXS = 1 << 20;

int i,j,x,n,m,k,u,v,w,tot,g,ts,ans,Mask;
int head[MAXN],s[MAXK];
int dist[MAXK][MAXN],f[MAXS][MAXK];
bool visited[MAXN];

struct Edge
{
    int to,w,nxt;
} e[MAXM << 1];

inline void addedge(int u,int v,int w)
{
    tot++;
    e[tot] = (Edge){v,w,head[u]};
    head[u] = tot;
}
inline void dijkstra(int s)
{
    int i,v,w;
    priority_queue< pair<int,int> > q;
    pair<int,int> cur;
    for (i = 1; i <= n; i++) 
    {
        dist[s][i] = INF;
        visited[i] = false;
    }
    dist[s][s] = 0;
    q.push(make_pair(0,s));
    while (!q.empty())
    {
        cur = q.top();
        q.pop();
        if (visited[cur.second]) continue;
        visited[cur.second] = true;
        for (i = head[cur.second]; i; i = e[i].nxt)
        {
            v = e[i].to;
            w = e[i].w;
            if (dist[s][cur.second] + w < dist[s][v])
            {
                dist[s][v] = dist[s][cur.second] + w;
                q.push(make_pair(-dist[s][v],v));
            }
        }
    }
}
int main()
{
    
    scanf("%d%d%d",&n,&m,&k);
    for (i = 1; i <= m; i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
        addedge(v,u,w);    
    }
    scanf("%d",&g);
    for (i = 1; i <= g; i++)    
    {
        scanf("%d%d",&u,&v);
        s[v] |= (1 << (u - 2));    
    }
    for (i = 1; i <= k + 1; i++) dijkstra(i);
    Mask = (1 << k) - 1;
    for (i = 0; i <= Mask; i++)
    {
        for (j = 1; j <= k + 1; j++)
        {
            f[i][j] = INF;
        }
    }
    for (i = 2; i <= k + 1; i++) 
    {
        if (!s[i])
            f[1 << (i - 2)][i] = dist[i][1];
    }
    f[0][1] = 0;
    for (i = 0; i <= Mask; i++)
    {
        for (j = 1; j <= k + 1; j++)
        {
            for (x = 2; x <= k + 1; x++)
            {
                ts = i | (1 << (x - 2));
                if (((s[x] & i) == s[x]) && f[i][j] + dist[j][x] < f[ts][x])
                    f[ts][x] = f[i][j] + dist[j][x];    
            }    
        }    
    }
    ans = INF;
    for (i = 1; i <= k + 1; i++) ans = min(ans,f[Mask][i] + dist[i][n]);
    printf("%d\n",ans);
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9343444.html