[USACO07FEB]荷叶塘Lilypad Pond

题目

链接[https://www.luogu.org/problemnew/show/P1606]

解法

因为我们要求释放荷叶的最小个数,可以联想到最短路。

然后我们考虑从当前节点出发能到哪些点,然后向周围点连一条长度为1的边就可以了。

然后方案数就是最短路计数。

但是从当前点出发可能连到一个已经有的荷叶,是不需要花费的,我们就以这个荷叶为跳板,

看他能免费到哪些节点,dfs建一下边就可以了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <vector>
#include <queue>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=30*30+15;
vector<int> G[maxn];

void add_edge(int u,int v) {
    G[u].push_back(v);
}

int n,m,s,t;
int get_id(int i,int j) {
    return (i-1)*m+j;
}
bool vis[maxn];
int a[35][35];

int dx[]={1,1,-1,-1,2,2,-2,-2};
int dy[]={2,-2,2,-2,-1,1,-1,1};

void build(int cur,int x,int y) {
    if(vis[get_id(x,y)]) return;
    vis[get_id(x,y)]=1;
    for(int i=0;i<8;i++) {
        int xx=x+dx[i],yy=y+dy[i];
        if(xx<1||yy<1||xx>n||yy>m||vis[get_id(xx,yy)]) continue;
        if(a[xx][yy]==2) continue;
        if(a[xx][yy]==1) build(cur,xx,yy);
        else {
            add_edge(cur,get_id(xx,yy));
            vis[get_id(xx,yy)]=1;
        }
    }
}


int dis[maxn];
ll num[maxn];

void spfa() {
    del(vis,0);
    for(int i=1;i<=n*m;i++) dis[i]=INF;
    queue<int> q;
    dis[s]=0;vis[s]=1;q.push(s);num[s]=1ll;
    while(!q.empty()) {
        int u=q.front();q.pop();vis[u]=0;
        for(int i=0;i<G[u].size();i++) {
            int v=G[u][i];
            if(dis[v]>dis[u]+1) {
                num[v]=num[u];
                dis[v]=dis[u]+1;
                if(!vis[v]) {
                    vis[v]=1;
                    q.push(v);
                }
            }
            else if(dis[v]==dis[u]+1) num[v]+=num[u];
        }
    }
}

int main()
{
    read(n),read(m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) {
            read(a[i][j]);
            if(a[i][j]==3) s=get_id(i,j);
            if(a[i][j]==4) t=get_id(i,j);
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) {
            if(a[i][j]==1||a[i][j]==2) continue;
            del(vis,0);build(get_id(i,j),i,j);
        }
    spfa();
    if(dis[t]==INF) printf("-1\n");
    else printf("%d\n%lld\n",dis[t]-1,num[t]);
    return 0;
}
View Code

 

posted @ 2018-10-24 20:43  Mr_asd  阅读(134)  评论(0)    收藏  举报