poj 4019 Immediate Delivery

来源:互联网 发布:monkey社交软件下载 编辑:程序博客网 时间:2024/06/09 09:06

          dp。可以用spfa,也可以暴力一些的dp,我这里用的是暴力一些的dp。。。容易写一些。这道题的关键是输出路径,算是路径输出的好题吧!首先我们用dp[ i ][ j ]表示当前状态为 i (将点压缩) 时,最后访问的点为 j 时的最短距离,最后的答案就是两个除去第一个点的两个互补集合 i 和 ((1 << n) - 1 - i) | 1,的路程的和。然后先Floyd 预处理一下每两对点之间的距离,然后暴力枚举 状态,然后递推就可以了。输出路径比较恶心,需要将Floyd处理后的两点之间路径还原为原图上的路径,这样的话因为点比较少,我们直接暴力dfs搜索就可以了。详细看代码吧,路径输出那块儿实在是恶心。。。

#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cstdio>#include<cmath>#define LL long long#define CLR(a, b) memset(a, b, sizeof(a))using namespace std;const int N = 20;const int M = 300000;const int INF = 0x3f3f3f3f;int G[N][N], dp[M][N], Len[M];int n, E[N][N], vis, pt[M][N], lpt[M];void Floyd(){    for(int k = 0; k < n; k ++)        for(int i = 0; i < n; i ++)            if(G[i][k] >= 0) for(int j = 0; j < n; j ++)                if(G[k][j] >= 0 && (G[i][j] < 0 || G[i][j] > G[i][k] + G[k][j]))                    G[i][j] = G[i][k] + G[k][j];}int Solve(){    CLR(dp, -1);dp[1][0] = 0;CLR(Len, -1);CLR(pt, -1);    for(int i = 0; i < (1 << n); i ++)        for(int j = 0; j < n; j ++)            if(dp[i][j] >= 0)            {                for(int k = 0; k < n; k ++)                {                    if((1 << k) & i) continue;                    int tmp = i | (1 << k);                    if(dp[tmp][k] < 0 || dp[tmp][k] > dp[i][j] + G[j][k])//看这个转移状态应该很容易想到Spfa吧!                        dp[tmp][k] = dp[i][j] + G[j][k], pt[tmp][k] = j;                }                if(Len[i] < 0 || Len[i] > dp[i][j]) Len[i] = dp[i][j], lpt[i] = j;            }    int ret = INF;    for(int i = 1; i < (1 << n); i ++)    {        int bt = (1 << n) - 1 - i, tmp = INF;        if(Len[i] >= 0 && Len[bt | 1] >= 0) tmp = max(Len[i], Len[bt | 1]);        if(tmp < ret)        {            ret = tmp;            vis = i;        }    }    return ret;}vector<int>path;bool dfs(int u, int v, int q, int len){    if(len > G[q][v]) return 0;    if(u == v)    {        return len == G[q][v];    }    for(int i = 0; i < n; i ++)    {        if(E[u][i] > 0 && E[u][i] <= G[q][v])        {            if(dfs(i, v, q, len + E[u][i]))            {                path.push_back(u + 1);                return 1;            }        }    }    return 0;}void find(int val, int u){    int v = pt[val][u];    if(v < 0) return;    dfs(v, u, v, 0);    find(val - (1 << u), v);}void Path(int val){    path.clear();path.push_back(lpt[val] + 1);    find(val, lpt[val]);    printf("%d", path.size() - 1);    for(int i = path.size() - 1; i >= 0; i --)    {        printf(" %d", path[i]);    }puts("");}int main(){    int m, u, v, c;    while(scanf("%d%d", &n, &m) != EOF)    {        CLR(G, -1);        for(int i = 0; i < m; i ++)        {            scanf("%d%d%d", &u, &v, &c);            u --, v --;G[i][i] = 0;            G[u][v] = G[v][u] = c;        }        memcpy(E, G, sizeof(E));        Floyd();        printf("%d\n", Solve());        Path(vis);vis = ((1 << n) - 1 - vis) | 1;        Path(vis);    }}