pku3311 Hie with the Pie(spfa+状态压缩)

题意:给定一个n+1个点的有向图和起点,求经过其余n个点然后回到起点的最短路径。。(n<=10)

分析:看到这么小的数据,就知道不是普通的最短路了,首先,n 这么小,应该联想到的应该是状态压缩吧,每一个位表示经过了哪一个点。。。

dp[i][j] 表示到达点i 状态为j 时的最短路径长度,一开始忽略了一点,就是更新过的点,完全有可能再更新的,所以不能单纯记录是否更新过该状态,所以就想到了用spfa,将更新过的点入队,,继续拓展……

View Code
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

const int N = (1 << 11) + 10;
int map[15][15], n;
int dp[15][N];
bool vis[15][N];

struct node
{
    int v,state;
    node(){}
    node(int v,int state):v(v),state(state){}
};

void spfa()
{
    memset(vis,false,sizeof(vis));
    memset(dp,-1,sizeof(dp));
    dp[0][0]=0;
    queue<node> Q;
    Q.push(node(0,0));
    vis[0][0]=true;
    while(!Q.empty())
    {
        node tmp=Q.front();
        Q.pop();
        vis[tmp.v][tmp.state]=false;
        for(int i=0;i<n;++i)
        {
            if(tmp.v==i) continue;
            if(dp[i][tmp.state|(1<<i)]==-1 || dp[i][tmp.state|(1<<i)]>dp[tmp.v][tmp.state]+map[tmp.v][i])
            {
                dp[i][tmp.state|(1<<i)]=dp[tmp.v][tmp.state]+map[tmp.v][i];
                if(!vis[i][tmp.state|(1<<i)])
                {
                    vis[i][tmp.state|(1<<i)]=true;
                    Q.push(node(i,tmp.state|(1<<i)));
                }
            }
        }
    }
}
int main()
{
    while(scanf("%d", &n) == 1 && n)
    {
        n++;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)
                scanf("%d", &map[i][j]);
        spfa();
        printf("%d\n", dp[0][(1<<n)-1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/nanke/p/2661591.html