这个题其实算是个最短路计数,建图的直观思想很简单,但是很显然有一个地方没法处理,就是有的时候通过两条路走到同一个地方的话方案数会计算两次。我们发现加上原有的莲花就很难处理,会计算重复。我们要想办法避免这种情况,一开始想联通块,其实已经差不多了,就是把已经有的互相联通的看成一块,然后和水暴力连边,最后跑裸的最短路就行了。(原来有0边就不能直接跑最短路计数啊)。

题干:

为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘。这个长方形的池子被分成了M行N列个方格(≤M,N≤)。一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是美丽、纯净、湛蓝的水。

贝西正在练习芭蕾舞,她站在一朵莲花上,想跳到另一朵莲花上去,她只能从一朵莲花跳到另一朵莲花上,既不能跳到水里,也不能跳到岩石上。

贝西的舞步很像象棋中的马步:每次总是先横向移动一格,再纵向移动两格,或先纵向移动两格,再横向移动一格。最多时,贝西会有八个移动方向可供选择。

约翰一直在观看贝西的芭蕾练习,发现她有时候不能跳到终点,因为中间缺了一些荷叶。于是他想要添加几朵莲花来帮助贝西完成任务。一贯节俭的约翰只想添加最少数量的莲花。当然,莲花不能放在石头上。

请帮助约翰确定必须要添加的莲花的最少数量,以及有多少种放置这些莲花的方法。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;++i)
#define lv(i,a,n) for(register int i = a;i >= n;--i)
#define clean(a) memset(a,0,sizeof(a))
const int INF = ;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
struct node
{
int l,r,nxt;
}a[];
int lst[],len = ;
int n,m,fx,fy,sx,sy;
int id[][],mp[][];
int vis[][];
const int dx[]={,,-,-,,,-,-};
const int dy[]={,,,,-,-,-,-};
int dis[];
ll to[];
int used[];
void add(int x,int y)
{
a[++len].l = x;
a[len].r = y;
a[len].nxt = lst[x];
lst[x] = len;
}
void dfs(int idx,int x,int y)
{
if(vis[x][y] == ) return;
vis[x][y] = ;
// cout<<idx<<" "<<x<<" "<<y<<endl;
for(int i = ;i < ;i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if(nx > n || ny > m || nx < || ny < || vis[nx][ny] == ) continue;
// cout<<nx<<" "<<ny<<endl;
if(mp[nx][ny] == ) dfs(idx,nx,ny);
else if(mp[nx][ny] != )
{
vis[nx][ny] = ;
// cout<<idx<<" "<<id[nx][ny]<<endl;
add(idx,id[nx][ny]);
}
}
}
void spfa()
{
int s = id[sx][sy];
int t = id[fx][fy];
queue <int> q;
duke(i,,n * m)
{
dis[i] = INF;
}
dis[s] = ;to[s] = 1LL;
q.push(s);
while(!q.empty())
{
int now = q.front();
q.pop();
used[now] = ;
for(int k = lst[now];k;k = a[k].nxt)
{
int y = a[k].r;
if(dis[y] > dis[now] + )
{
dis[y] = dis[now] + ;
to[y] = to[now];
if(used[y] == )
{
q.push(y);
used[y] = ;
}
}
else if(dis[y] == dis[now] + )
to[y] += to[now];
}
}
if(dis[t] < INF) printf("%d\n%lld\n",dis[t] - ,to[t]);
else
printf("-1\n");
}
int main()
{
read(n);read(m);
duke(i,,n)
{
duke(j,,m)
{
read(mp[i][j]);
id[i][j] = (i - ) * m + j;
if(mp[i][j] == )
{
sx = i;
sy = j;
}
if(mp[i][j] == )
{
fx = i;
fy = j;
}
}
}
duke(i,,n)
{
duke(j,,m)
{
if(!mp[i][j] || mp[i][j] == )
{
// cout<<i<<" "<<j<<endl;
clean(vis);
dfs(id[i][j],i,j);
}
}
}
spfa();
return ;
}

P1606 [USACO07FEB]白银莲花池Lilypad Pond的更多相关文章

  1. bzoj1698 / P1606 [USACO07FEB]白银莲花池Lilypad Pond

    P1606 [USACO07FEB]白银莲花池Lilypad Pond 转化为最短路求解 放置莲花的方法如果直接算会有重复情况. 于是我们可以先预处理和已有莲花之间直接互相可达的点,将它们连边(对,忽 ...

  2. Luogu 1606 [USACO07FEB]白银莲花池Lilypad Pond

    感觉应当挺简单的,但是弄了好久……菜死了 如果不考虑那些为$1$的点,直接跑个最短路计数就好了,但是我们现在有一些边可以不用付出代价,那么只要在连边的时候先预处理搜一下就好了. 原来的想法是拆点,但是 ...

  3. 最短路【洛谷P1606】 [USACO07FEB]荷叶塘Lilypad Pond

    P1606 [USACO07FEB]荷叶塘Lilypad Pond 为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘.这个长方形的池子被分成了M行N列个方格(1≤M,N≤30).一些格子是坚固得令 ...

  4. 洛谷 P1606 [USACO07FEB]荷叶塘Lilypad Pond 解题报告

    P1606 [USACO07FEB]荷叶塘Lilypad Pond 题目描述 FJ has installed a beautiful pond for his cows' aesthetic enj ...

  5. P1606 [USACO07FEB]荷叶塘Lilypad Pond(最短路计数)

    P1606 [USACO07FEB]荷叶塘Lilypad Pond 题目描述 FJ has installed a beautiful pond for his cows' aesthetic enj ...

  6. BZOJ 1632: [Usaco2007 Feb]Lilypad Pond

    题目 1632: [Usaco2007 Feb]Lilypad Pond Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 390  Solved: 109[ ...

  7. 1632: [Usaco2007 Feb]Lilypad Pond

    1632: [Usaco2007 Feb]Lilypad Pond Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 404  Solved: 118[Sub ...

  8. 【luogu P1606 [USACO07FEB]荷叶塘Lilypad Pond】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1606 这个题..第一问很好想,但是第二问,如果要跑最短路计数的话,零边权的花怎么办? 不如这样想,如果这个点 ...

  9. [洛谷P1606] [USACO07FEB] 荷叶塘Lilypad Pond

    Description 为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘.这个长方形的池子被分成了M行N列个方格(1≤M,N≤30).一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是 ...

随机推荐

  1. elk大纲

    一.ELK功能概览 1.检索 2.数据可视化--实时监控(实时刷新) nginx 访问量 ip地区分布图(大数据) 3.zabbix 微信联动报警 4.大数据日志分析平台(基于hadoop) 二.ka ...

  2. 模板—splay

    #include<iostream> #include<cstdio> #define cin(x) scanf("%d",&x) using na ...

  3. __cdecl、__stdcall、__fastcall 与 __pascal 浅析

    call 指令与 retn 指令 首先我们得了解 CALL 和 RETN 指令的作用,才能更好地理解调用规则,这也是先决条件. 实际上,CALL 指令就是先将下一条指令的 EIP 压栈,然后 JMP ...

  4. The King’s Ups and Downs(HDU 4489,动态规划递推,组合数,国王的游戏)

    题意: 给一个数字n,让1到n的所有数都以波浪形排序,即任意两个相邻的数都是一高一低或者一低一高 比如:1324   4231,再比如4213就是错的,因为4高,2低,接下来1就应该比2高,但是它没有 ...

  5. [Algorithm] 3. Digit Counts

    Description Count the number of k's between 0 and n. k can be 0 - 9. Example if n = 12, k = 1 in [0, ...

  6. UVA - 208 Firetruck(并查集+dfs)

    题目: 给出一个结点d和一个无向图中所有的边,按字典序输出这个无向图中所有从1到d的路径. 思路: 1.看到紫书上的提示,如果不预先判断结点1是否能直接到达结点d,上来就直接dfs搜索的话会超时,于是 ...

  7. pxc增量恢复

    解流 xbstream -x < fullbackup2.xbstream -C /data/fullbackup xbstream -x < fullbackup2.xbstream - ...

  8. 【C++】实现记录软件计时时间

    利用getTickCount()和getTickFrequency()函数实现计时 double time0 = static_cast<double>(getTickCount()); ...

  9. 【01】CSS制作的图形

    [01]CSS制作的图形   绘制五角星:   通过border绘制三角形.然后通过transfrom来旋转35度. 绘制对称的图形,最后绘制顶部的三角形即可.   元素本身,加上:before和:a ...

  10. nyoj 31 5个数求最值

    5个数求最值 时间限制:1000 ms  |  内存限制:65535 KB 难度:1   描述 设计一个从5个整数中取最小数和最大数的程序   输入 输入只有一组测试数据,为五个不大于1万的正整数 输 ...