COJ 1175 A Tour Around Hangzhou (最短路+状态压缩DP)

模型:给一个n个点的无向带权图,求从指定起点出发,经过指定的k个点(顺序不定)最后回到起点的最小代价。

数据范围:n<=10^4, m<=10^5, k<15

分析:先求最短路,求出从指定的k+1(含起点)个点到其他点的最小代价,然后建立k+1个点之间的最小代价邻接矩阵。最后用状态压缩DP求结果(状态压缩DP参考上一篇)。

View Code
#include <stdio.h>

#include <string.h>

#include <queue>

using namespace std;

#define MIN(a,b) ((a)<(b)?(a):(b))

#define INF 0x3f3f3f3f

#define N 10010

#define M 200010

#define K 15

int n,m,k,e;

int first[N],next[M],v[M],w[M];

int id[K];

int d[K][N];

bool inq[N];



int g[K][K];

int dp[1<<K][K];



void init()

{

    e=0;

    memset(first,-1,sizeof(first));

}

void add(int a,int b,int c)

{

    v[e]=b;

    w[e]=c;

    next[e]=first[a];

    first[a]=e++;

}

void spfa(int i)

{

    int a,b,j;

    a=id[i];

    queue<int>q;



    memset(inq,0,sizeof(inq));

    memset(d[i],0x3f,sizeof(d[i]));

    d[i][a]=0;



    q.push(a);

    inq[a]=1;



    while(!q.empty())

    {

        a=q.front(),q.pop();

        inq[a]=0;



        for(j=first[a];j!=-1;j=next[j])

        {

            b=v[j];

            if(d[i][b]>d[i][a]+w[j])

            {

                d[i][b]=d[i][a]+w[j];

                if(!inq[b]) inq[b]=1,q.push(b);

            }

        }

    }

}

int DP(int s,int last)

{

    if(dp[s][last]!=-1) return dp[s][last];



    int ns=s^(1<<last);

    if(ns==1)   return g[0][last];



    int ret=INF;

    for(int i=1;i<k;i++)    if((ns>>i)&1)

    {

        ret=MIN(ret,DP(ns,i)+g[i][last]);

    }

    return dp[s][last]=ret;

}

int main()

{

    int i,j,a,b,c;

    while(~scanf("%d%d%d",&n,&m,&k))

    {

        init();

        while(m--)

        {

            scanf("%d%d%d",&a,&b,&c);

            add(a,b,c);

            add(b,a,c);

        }

        k++;

        for(i=0;i<k;i++)

        {

            scanf("%d",&id[i]);

            spfa(i);

        }

        for(i=0;i<k;i++)

        {

            for(j=0;j<k;j++)

            {

                g[i][j]=d[i][id[j]];

            }

        }

        int ans=INF;

        memset(dp,-1,sizeof(dp));

        for(i=0;i<k;i++)

        {

            ans=MIN(ans,DP((1<<k)-1,i)+g[0][i]);

        }

        if(ans<INF) printf("%d\n",ans);

        else    puts("What a pity");

    }

    return 0;

}

 

你可能感兴趣的:(round)