P1713题解

洛谷 P1713题解

蒟蒻的第一篇黑题题解,如有错误请多见谅。

题意

在 $\hspace{0.05cm}n \times n $ ($2\le n\le10$)的矩阵中有 $m$ 个点无法通过,从左下角右上角的最长路和最短路距离之差

推理

考虑直接爆搜插头 dp。

不会插头 dp 的同学请先完成这道模板题

插头 dp 求回路很简单,那求一条路呢?

那就补一条与别的路不相交的路进去嘛!

如图,红色为禁止通过的格子,蓝色为原矩阵。

样例则变为(黄色为无法通过的点)

显然,原图中的最长路和最短路之差等于新图的最长回路和最短回路之差。

所以只需储存当前插头状态的最大值和最小值,到边界时取最大和最小即可。

因为是从左下到右上的最短和最长路,所以回路要从新图的左下角(绿色)往右上角(玫红色)扫。

时间复杂度 $\hspace{0.05cm} O(n^22^n) $。

Show me the code.

#include <bits/stdc++.h>
using namespace std;
const int maxn=114514;
struct point{
    int nt,stat,maxx,minx;
}a[2][2<<12];
int n,i,j,k,m,now=0,maxx=-0x7fffffff,minx=0x7fffffff,x,y;
int nxt[maxn];
int cnt[2];
bool flag[15][15];
void insert(int stat,int maxx,int minx){
    int tmp=stat%maxn;
    for(int i=nxt[tmp];i;i=a[now][i].nt)
      if(a[now][i].stat==stat){
        a[now][i].maxx=max(a[now][i].maxx,maxx);
        a[now][i].minx=min(a[now][i].minx,minx);
        return ;
      }
    a[now][++cnt[now]].stat=stat;
    a[now][cnt[now]].maxx=maxx;
    a[now][cnt[now]].minx=minx;
    a[now][cnt[now]].nt=nxt[tmp];
    nxt[tmp]=cnt[now];
}//hash
int main() {
    memset(flag,false,sizeof(flag));
    scanf("%d%d",&n,&m);
    for(i=1;i<=n+2;i++)
      for(j=1;j<=n+2;j++)
        flag[i][j]=true;
    for(i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        flag[x+2][y+2]=false;
    }
    for(i=2;i<=n+1;i++)
      flag[i][2]=flag[2][i]=false;
    insert(0,0,0);
   //插头dp
    for(i=n+2;i>=1;i--){
        for(j=1;j<=cnt[now];j++){
            a[now][j].stat<<=2;
        }
        for(j=1;j<=n+2;j++){
            int pre=now;now^=1;cnt[now]=0;
            memset(nxt,0,sizeof(nxt));
            for(k=1;k<=cnt[pre];k++){
                int tmp1=(a[pre][k].stat>>(2*j-2))%4,tmp2=(a[pre][k].stat>>(2*j))%4;
                if(flag[i][j]==false){
                    if(tmp1==0 && tmp2==0){
                        insert(a[pre][k].stat,a[pre][k].maxx,a[pre][k].minx);
                    }
                }
                else{
                    if(tmp1==0 && tmp2==0){
                        if(flag[i][j+1]==true && flag[i-1][j]==true) insert(a[pre][k].stat+(1<<(2*j-2))+(2<<(2*j)),a[pre][k].maxx+1,a[pre][k].minx+1);
                        if(i!=n+2 || j!=1)insert(a[pre][k].stat,a[pre][k].maxx,a[pre][k].minx);
                    }
                    if(tmp1>0 && tmp2==0){
                        if(flag[i][j+1]==true) insert(a[pre][k].stat-(tmp1<<(2*j-2))+(tmp1<<(2*j)),a[pre][k].maxx+1,a[pre][k].minx+1);
                        if(flag[i-1][j]==true) insert(a[pre][k].stat,a[pre][k].maxx+1,a[pre][k].minx+1);
                    }
                    if(tmp1==0 && tmp2>0){
                        if(flag[i][j+1]==true) insert(a[pre][k].stat,a[pre][k].maxx+1,a[pre][k].minx+1);
                        if(flag[i-1][j]==true) insert(a[pre][k].stat-(tmp2<<(2*j))+(tmp2<<(2*j-2)),a[pre][k].maxx+1,a[pre][k].minx+1);
                    }
                    if(tmp1==1 && tmp2==2){
                        if(i==1 && j==n+2){
                            maxx=max(maxx,a[pre][k].maxx);
                            minx=min(minx,a[pre][k].minx);
                        }
                    }
                    if(tmp1==1 && tmp2==1){
                        int count=1;
                        for(int num=j+1;num<=n+2;num++){
                            if((a[pre][k].stat>>(num*2))%4==1) count++;
                            if((a[pre][k].stat>>(num*2))%4==2) count--;
                            if(count==0){
                                insert(a[pre][k].stat-(1<<(2*j-2))-(1<<(2*j))-(1<<(2*num)),a[pre][k].maxx+1,a[pre][k].minx+1);
                                break;
                            }
                        }
                    }
                    if(tmp1==2 && tmp2==2){
                        int count=1;
                        for(int num=j-2;num>=0;num--){
                            if((a[pre][k].stat>>(num*2))%4==1) count--;
                            if((a[pre][k].stat>>(num*2))%4==2) count++;
                            if(count==0){
                                insert(a[pre][k].stat-(2<<(2*j-2))-(2<<(2*j))+(1<<(2*num)),a[pre][k].maxx+1,a[pre][k].minx+1);
                                break;
                            }
                        }
                    }
                    if(tmp1==2 && tmp2==1) insert(a[pre][k].stat-(2<<(2*j-2))-(1<<(2*j)),a[pre][k].maxx+1,a[pre][k].minx+1);
                }
              }
        }
    }
    printf("%d",maxx-minx);
    return 0;
}

笔者码风奇特,不喜勿喷。

这份代码吸氧以后141 ms

这题做完以后可以试试 POJ1739 Tony's Tour 是 cdq 论文里的题,和本题思路大同小异。

posted @ 2023-08-08 13:49  monster_hunterqwq  阅读(13)  评论(0编辑  收藏  举报  来源