[Luogu] 飞扬的小鸟

杀马特。学长 韩版系。学妹 提交于 2020-11-24 19:29:37

https://www.luogu.org/problemnew/show/P1941

Bfs or Dp

#include <bits/stdc++.h>

using namespace std;
const int N = 1e4 + 10;

#define gc getchar()
#define oo 99999999

struct Node_1 {
    int X, D, U;
} P[N];
struct Node_2 {
    int U, D;
} M[N];
struct node {
    int x, y, step;
};

int n, m, k;
int Answer = oo, Maxx;

queue <node> Q;

inline int read() {
    int x = 0;
    char c = gc;
    while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    return x;
}

int up, down;
int vis[N][1000];

inline void Bfs() {
    for(int i = m; i >= 1; i --) {
        node now;
        now.x = 2;
        down = i - M[1].D, up = i + M[1].U;
        if(down > P[2].D && down < P[2].U && vis[2][down] == 0) {
            now.y = down;
            now.step = 0;
            vis[now.x][now.y] = 1;
            Q.push(now);
        }

        if(up > P[2].D && up < P[2].U && vis[2][up] == 0) {
            now.y = min(up, m);
            vis[now.x][now.y] = 1;
            now.step = 1;
            Q.push(now);
        }

    }
    while(!Q.empty()) {
        node topp = Q.front();
        Q.pop();
        Maxx = max(Maxx, topp.x);
        if(topp.x == n + 1) {
            Answer = min(Answer, topp.step);
            continue ;
        }
        int y = topp.y, x = topp.x;
        node nxt;
        nxt.x = x + 1;
        down = y - M[x].D, up = y + M[x].U;
        if(down > P[x + 1].D && down < P[x + 1].U) {
            nxt.y = down;
            nxt.step = topp.step;
            if(vis[nxt.x][nxt.y] == 0) {
                vis[nxt.x][nxt.y] = nxt.step;
                Q.push(nxt);
            } else {
                if(vis[nxt.x][nxt.y] > nxt.step) {
                    Q.push(nxt);
                    vis[nxt.x][nxt.y] = nxt.step;
                }
            }
        }
        nxt.y = up;
        nxt.step = topp.step;
        up = min(up, m);
        while(up > P[x + 1].D && up < P[x + 1].U) {
            nxt.y = min(nxt.y, m);
            if(vis[nxt.x][nxt.y] == 0) {
                nxt.step ++;
                vis[nxt.x][nxt.y] = nxt.step;
                Q.push(nxt);
            } else {
                if(vis[nxt.x][nxt.y] > nxt.step + 1) {
                    nxt.step ++;
                    Q.push(nxt);
                    vis[nxt.x][nxt.y] = nxt.step;
                }
            }
            if(nxt.y == m) break;
            nxt.y += M[x].U;
            up = min(nxt.y, m);
        }
    }
}

int main() {
    n = read();
    m = read();
    k = read();
    for(int i = 1; i <= n; i ++)
        M[i].U = read(), M[i].D = read(), P[i].U = m + 1;
    P[n + 1].U = m + 1;
    for(int i = 1; i <= k; i ++) {
        int X = read() + 1;
        P[i].X = X;
        P[X].D = read();
        P[X].U = read();
    }
    Bfs();
    if(Answer != oo) cout << 1 << "\n" << Answer;
    else {
        cout << 0 << "\n";
        int js(0);
        for(int i = 1; i <= k; i ++) if(P[i].X <= Maxx) js ++;
        cout << js;
    }

    return 0;
}
/*
5 5 0
3 3
2 1
2 3
2 1
3 2
*/
View Code
#include<cstdio>
#include<cctype>
#include<algorithm>
#define N 10003
#define M 1003
#define For(i,j,k) for(int i=j;i<=k;++i)
int read() {
    int x=0,l=1;
    char ch=getchar();
    while(!isdigit(ch)) {
        if (ch=='-') l=-1;
        ch=getchar();
    }
    while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    return x*l;
}
using namespace std;
int a[N][M],x[N],y[N],hi[N]; //a存到当前点的最优步数
short hk[M<<1],wal[M<<1]; //hk记列,wal记行,这只是循环队列,不要在意变量名
bool fl[N][M],mp[N][M],li[N]; //fl--某个点有没有被走过,mp--某个点有没有管子,li--记录某一列能不能到
int main() {
    int an,n=read(),m=read(),k=read(),mo,ha,jzm,l=0,r,ac,p=0,kk,ff;
    ac=m<<1;
    For(i,0,n-1) x[i]=read(),y[i]=read(),hi[i]=10000; //hi记录某一列上限,如果是最大值表示无上限
    For(i,1,k) {
        jzm=read(),mo=read(),ha=read(); //不要在意变量名x2
        For(j,1,mo) mp[jzm][j]=1;
        For(j,ha,m) mp[jzm][j]=1;
        hi[jzm]=ha-1; //mp,hi标记
    }
    r=m;
    For(i,1,m) wal[i]=i; //第0列入队
    while(l<r) {
        l++;
        mo=hk[l%ac];
        ha=wal[l%ac];
        ff=an=0;
        li[mo]=1;
        if (mo==n) continue;
        kk=min(m,hi[mo+1]);
        for(int i=ha+x[mo]; i<=kk; i+=x[mo]) { //枚举当前点可以到的点
            an++;
            if (mp[mo+1][i]) continue; //判断当前有没有管道(下面的,碰上面管道就退循环了)
            if (!fl[mo+1][i]) { //没走过就入队
                fl[mo+1][i]=1;
                r++;
                hk[r%ac]=mo+1;
                wal[r%ac]=i;
                a[mo+1][i]=a[mo][ha]+an;
            } else if (a[mo+1][i]>a[mo][ha]+an) a[mo+1][i]=a[mo][ha]+an; //更新值
            if (fl[mo][i]&&a[mo][i]<=a[mo][ha]+an) {
                ff=1;
                break;
            }
            //重要剪枝!如果当前点顶上有点比他更优那就可以退了
            //但是在这之前的循环是必要的,因为这时走的点是他顶上那个点走不到的
        }
        if (!mp[mo+1][m]&&!ff) { //特判到顶的情况
            if (!fl[mo+1][m]) {
                fl[mo+1][m]=1;
                r++;
                hk[r%ac]=mo+1;
                wal[r%ac]=m;
                a[mo+1][m]=a[mo][ha]+an+1;
            } else if (a[mo+1][m]>a[mo][ha]+an+1) a[mo+1][m]=a[mo][ha]+an+1;
        }
        if (ha-y[mo]>0) { //特判下降情况
            jzm=ha-y[mo];
            if (!mp[mo+1][jzm]) {
                if (!fl[mo+1][jzm]) {
                    fl[mo+1][jzm]=1;
                    r++;
                    hk[r%ac]=mo+1;
                    wal[r%ac]=jzm;
                    a[mo+1][jzm]=a[mo][ha];
                } else if (a[mo+1][jzm]>a[mo][ha]) a[mo+1][jzm]=a[mo][ha];
            }
        }
    }
    for(int i=n; i>=0; i--) //输出
        if (li[i]) {
            if (i==n) {
                printf("1\n");
                an=2100000000;
                For(j,1,m) if (an>a[n][j]&&fl[n][j]) an=a[n][j];
                printf("%d\n",an);
                return 0;
            }
            printf("0\n");
            an=0;
            for(int j=i; j>=1; j--) if (hi[j]!=10000) an++;
            printf("%d\n",an);
            return 0;
        }
}
View Code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXDP=100000;
int l[10010],h[10010];
int dp[10010][1010];
int x[10010],y[10010];
bool p[10010];
int main() {
    int n,i,j,k,m,w;
    scanf("%d%d%d",&n,&m,&k);
    for(i=0; i<n; i++) {
        scanf("%d%d",&x[i],&y[i]);
        l[i]=0;
        h[i]=m+1;
    }
    l[n]=0;
    h[n]=m+1;
    for(i=0; i<k; i++) {
        scanf("%d",&w);
        scanf("%d%d",&l[w],&h[w]);
        p[w]=true;
    }
    for(i=1; i<=n; i++) {
        for(j=0; j<=m; j++) {
            dp[i][j]=MAXDP;
        }
    }
    dp[0][0]=MAXDP;
    for(i=1; i<=m; i++) {
        dp[0][i]=0;
    }
    for(i=1; i<=n; i++) {
        for(j=x[i-1]; j<=m; j++) {
            if(j==m) {
                for(w=m-x[i-1]; w<=m; w++) {
                    dp[i][j]=min(dp[i][j],dp[i-1][w]+1);
                    dp[i][j]=min(dp[i][j],dp[i][w]+1);
                }
            }
            dp[i][j]=min(dp[i][j],dp[i-1][j-x[i-1]]+1);
            dp[i][j]=min(dp[i][j],dp[i][j-x[i-1]]+1);
        }
        for(j=max(1,l[i]+1); j<=min(m-y[i-1],h[i]-1); j++) {
            dp[i][j]=min(dp[i][j],dp[i-1][j+y[i-1]]);
        }
        for(j=l[i]; j>=1; j--) {
            dp[i][j]=MAXDP;
        }
        for(j=h[i]; j<=m; j++) {
            dp[i][j]=MAXDP;
        }
    }
    int ans=MAXDP;
    int cnt=k;
    for(i=n; i>=1; i--) {
        for(j=l[i]+1; j<=h[i]-1; j++) {
            ans=min(ans,dp[i][j]);
        }
        if(ans<MAXDP) {
            break;
        }
        if(p[i]==true) {
            k--;
        }
    }
    if(cnt==k) {
        printf("1\n%d",ans);
    } else {
        printf("0\n%d",k);
    }
    return 0;
}
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!