P1606 [USACO07FEB]白银莲花池Lilypad Pond
Posted dukelv
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1606 [USACO07FEB]白银莲花池Lilypad Pond相关的知识,希望对你有一定的参考价值。
这个题其实算是个最短路计数,建图的直观思想很简单,但是很显然有一个地方没法处理,就是有的时候通过两条路走到同一个地方的话方案数会计算两次。我们发现加上原有的莲花就很难处理,会计算重复。我们要想办法避免这种情况,一开始想联通块,其实已经差不多了,就是把已经有的互相联通的看成一块,然后和水暴力连边,最后跑裸的最短路就行了。(原来有0边就不能直接跑最短路计数啊)。
题干:
为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘。这个长方形的池子被分成了M行N列个方格(1≤M,N≤30)。一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是美丽、纯净、湛蓝的水。 贝西正在练习芭蕾舞,她站在一朵莲花上,想跳到另一朵莲花上去,她只能从一朵莲花跳到另一朵莲花上,既不能跳到水里,也不能跳到岩石上。 贝西的舞步很像象棋中的马步:每次总是先横向移动一格,再纵向移动两格,或先纵向移动两格,再横向移动一格。最多时,贝西会有八个移动方向可供选择。 约翰一直在观看贝西的芭蕾练习,发现她有时候不能跳到终点,因为中间缺了一些荷叶。于是他想要添加几朵莲花来帮助贝西完成任务。一贯节俭的约翰只想添加最少数量的莲花。当然,莲花不能放在石头上。 请帮助约翰确定必须要添加的莲花的最少数量,以及有多少种放置这些莲花的方法。
代码:
#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 = 2147483647; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < ‘0‘ || c > ‘9‘) if(c == ‘-‘) op = 1; x = c - ‘0‘; while(c = getchar(), c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar(‘-‘), x = -x; if(x >= 10) write(x / 10); putchar(‘0‘ + x % 10); } struct node { int l,r,nxt; }a[100050]; int lst[2650],len = 0; int n,m,fx,fy,sx,sy; int id[35][35],mp[35][35]; int vis[35][35]; const int dx[]={2,1,-1,-2,2,1,-1,-2}; const int dy[]={1,2,2,1,-1,-2,-2,-1}; int dis[1650]; ll to[1650]; int used[1605]; 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] == 1) return; vis[x][y] = 1; // cout<<idx<<" "<<x<<" "<<y<<endl; for(int i = 0;i < 8;i++) { int nx = x + dx[i]; int ny = y + dy[i]; if(nx > n || ny > m || nx < 1 || ny < 1 || vis[nx][ny] == 1) continue; // cout<<nx<<" "<<ny<<endl; if(mp[nx][ny] == 1) dfs(idx,nx,ny); else if(mp[nx][ny] != 2) { vis[nx][ny] = 1; // 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,1,n * m) { dis[i] = INF; } dis[s] = 0;to[s] = 1LL; q.push(s); while(!q.empty()) { int now = q.front(); q.pop(); used[now] = 0; for(int k = lst[now];k;k = a[k].nxt) { int y = a[k].r; if(dis[y] > dis[now] + 1) { dis[y] = dis[now] + 1; to[y] = to[now]; if(used[y] == 0) { q.push(y); used[y] = 1; } } else if(dis[y] == dis[now] + 1) to[y] += to[now]; } } if(dis[t] < INF) printf("%d %lld ",dis[t] - 1,to[t]); else printf("-1 "); } int main() { read(n);read(m); duke(i,1,n) { duke(j,1,m) { read(mp[i][j]); id[i][j] = (i - 1) * m + j; if(mp[i][j] == 3) { sx = i; sy = j; } if(mp[i][j] == 4) { fx = i; fy = j; } } } duke(i,1,n) { duke(j,1,m) { if(!mp[i][j] || mp[i][j] == 3) { // cout<<i<<" "<<j<<endl; clean(vis); dfs(id[i][j],i,j); } } } spfa(); return 0; }
以上是关于P1606 [USACO07FEB]白银莲花池Lilypad Pond的主要内容,如果未能解决你的问题,请参考以下文章
青铜莲花池(Bronze Lilypad Pond, USACO 2007 Feb)
洛谷P2875 [USACO07FEB]牛的词汇The Cow Lexicon