题解 P3070 [USACO13JAN]岛游记Island Travels

Posted nhdr233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P3070 [USACO13JAN]岛游记Island Travels相关的知识,希望对你有一定的参考价值。

题面有点坑,翻译内容中没有指明n的范围,通过观察原题面得到$n \leq 15$并大致猜测这是一个状态压缩dp

最小生成树显然不可行,可以举例说明存在某种情况某边要经过两次或更多

对于任意一个岛屿$i$到任意一个岛屿$j$的最短距离显然是固定的,每个岛域之间的距离(不经过其他岛屿)可以用bfs预处理出来,初始状态只要将这个岛屿全部坐标位置全部入队即可

得到了任意两个岛屿之间的直接距离后(当然存在部分岛屿不可互达),在$ n \leq 15$时可以直接用$floyd$求解

现在得到任意两个节点之间的最短距离,显然直接dfs复杂度任然爆炸,dfs求解的复杂度是$O(n!)$

考虑状态压缩dp,设$S$为当前节点是否经过的状态集合,$v$为当前停留的节点,显然有$f(S,v)=min\ f(S‘,u)+dis(u,v)\$其中$S‘$中$v$为未达,很明显对于任意一个状态他最多转移$n$个状态

得到时间复杂度为$O(2^nn)$的状压

```
//2019/7/24->Riko->AtNCU->luoguP3070
#include<bits/stdc++.h>
template <typename T> inline void smin (T& x, T y) if (x > y) x = y;
//Believing heart is your power
using namespace std;
int getch ()
    int ch = getchar();
    return (ch == ‘.‘ or ch == ‘S‘ or ch == ‘X‘) ? ch : getch();


const int N = 55;
struct Point
    int x, y;
    Point (int x, int y) : x(x), y(y)
;
struct Len
    int x, y, l;
    Len (int x, int y, int l) : x(x), y(y), l(l)
;
int r, c, n, ind;
int type[N][N], idx[N][N], len[N][N], vis[N][N], hasgone[N];
int f[(1<<15)+64][16], Mx[4] = 0, 0, 1, -1, My[4] = 1, -1, 0, 0;
queue <Point> Find, Save[N];
queue <Len> Que;

void Getpoints (int x, int y)
    Find.push(Point(x, y)); Save[ind].push(Point(x, y));
    while (!Find.empty())
        Point tem = Find.front(); Find.pop();
        for (int i = 0; i < 4; ++i)
            int Nx = tem.x+Mx[i];
            int Ny = tem.y+My[i];
            if (idx[Nx][Ny]) continue;
            if (type[Nx][Ny] != 1) continue;
            idx[Nx][Ny] = ind;
            Find.push(Point(Nx, Ny));
            Save[ind].push(Point(Nx, Ny));
        
    

void Getlen (int id)
    while (!Save[id].empty())
        Point tem = Save[id].front(); Save[id].pop();
        Que.push(Len(tem.x, tem.y, 0)); vis[tem.x][tem.y] = true;
    
    while (!Que.empty())
        Len tem = Que.front(); Que.pop();
        for (int i = 0; i < 4; ++i)
            int Nx = tem.x+Mx[i];
            int Ny = tem.y+My[i];
            if (!type[Nx][Ny] or vis[Nx][Ny]) continue;
            if (idx[Nx][Ny]) smin(len[id][idx[Nx][Ny]], tem.l); continue;
            vis[Nx][Ny] = true;
            Que.push(Len(Nx, Ny, tem.l+1));
        
    

void work ()
    memset(f, 0x3f, sizeof(f));
    for (int i = 1; i <= ind; ++i) f[(1<<(i-1))][i] = 0;
    for (int x = 1; x < (1<<ind); ++x)
        for (int u = 1; u <= ind; ++u)
            if (!x&(1<<(u-1))) continue;
            for (int v = 1; v <= ind; ++v)
                if (x&(1<<(v-1))) continue;
                smin(f[x|(1<<(v-1))][v], f[x][u]+len[u][v]);
            
        
    
    int ans = INT_MAX;
    for (int i = 1; i <= ind; ++i) smin(ans, f[(1<<ind)-1][i]);
    printf("%d", ans);

void prepare ()
    scanf("%d %d", &r, &c);
    for (int i = 1; i <= r; ++i)
        for (int j = 1; j <= c; ++j)
            int ch = getch();
            if (ch == ‘X‘) type[i][j] = 1;
            if (ch == ‘S‘) type[i][j] = 2;
        
    
    for (int i = 1; i <= r; ++i)
        for (int j = 1; j <= c; ++j)
            if (!idx[i][j] and type[i][j] == 1)
                idx[i][j] = ++ind;
                Getpoints(i, j);
            
        
            //prepare for the distance
    memset(len, 0x3f, sizeof(len));
    for (int i = 1; i <= r; ++i)
        for (int j = 1; j <= c; ++j)
            if (idx[i][j] and !hasgone[idx[i][j]])
                memset(vis, 0, sizeof(vis));
                hasgone[idx[i][j]] = true;
                Getlen(idx[i][j]);
            
        
            //Get the cloest distance
    for (int i = 1; i <= ind; ++i)
        for (int j = i+1; j <= ind; ++j)
            for (int k = i+1; k < j; ++k)
                smin(len[i][j], len[i][k]+len[k][j]);
                len[j][i] = len[i][j];
            
        
              //floyd Part
    work();
int main () prepare();
```

以上是关于题解 P3070 [USACO13JAN]岛游记Island Travels的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2205 [USACO13JAN]画栅栏Painting the Fence

题解 P3608 [USACO17JAN]Balanced Photo平衡的照片

题解 P6004 [USACO20JAN]Wormhole Sort S

题解 P2937 [USACO09JAN]激光电话Laserphones

题解晋升者计数 Promotion Counting [USACO 17 JAN] [P3605]

洛谷P2205 [USACO13JAN]画栅栏Painting the Fence