luogu 2411 白银莲花池 && luogu 1606 Lilypad Pond

luogu 2411 :

题目背景

(Silver Lilypad Pond, USACO 2007 Feb)

题目描述

为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘。这个长方形的池子被分成

了M行N列个方格(1 ≤ M, N ≤ 30)。一些格子是坚固得令人惊讶的莲花,还有一些格子是

岩石,其余的只是美丽、纯净、湛蓝的水。

贝西正在练习芭蕾舞,她站在一朵莲花上,想跳到另一朵莲花上去,她只能从一朵莲花

跳到另一朵莲花上,既不能跳到水里,也不能跳到岩石上。

贝西的舞步很像象棋中的马步:每次总是先横向移动一格,再纵向移动两格,或先纵向

移动两格,再横向移动一格。最多时,贝西会有八个移动方向可供选择。

约翰一直在观看贝西的芭蕾练习,发现她有时候不能跳到终点,因为中间缺了一些荷叶。

于是他想要添加几朵莲花来帮助贝西完成任务。一贯节俭的约翰只想添加最少数量的莲花。

当然,莲花不能放在石头上。

请帮助约翰确定必须要添加的莲花的最少数量。在添加莲花最少的基础上,确定贝西从

起点跳到目标需要的最少步数。最后,确定满足添加的莲花数量最少时,步数最少的路径条

数。

输入格式

第一行:两个用空格分开的整数:M和N

第二行到M + 1行:第i + 1行有N个用空格分开的整数,描述了池塘第i行的状态:0 为水,1 为莲花,2 为岩石,3 为贝西所在的起点,4 为贝西想去的终点。

输出格式

第一行:一个整数:需要添加的莲花的最少数目;如果无解,则输出-1

第二行:一个整数:在添加莲花最少的基础上,贝西从起点跳到终点需要的最少步数;如果第一行是-1,不输出这行

第三行:一个整数:在添加莲花最少的基础上,步数等于第二行输出的路径条数;如果第一行是-1,不输出这行

输入输出样例

输入 #1
4 8 
0 0 0 1 0 0 0 0 
0 0 0 0 0 2 0 1 
0 0 0 0 0 4 0 0 
3 0 0 0 0 0 1 0 
(池塘分成四行八列,贝西的起点在第四行
第一列,想去的终点在第三行第六列,池塘
里一共有五朵莲花和一块石头)
输出 #1
2
6
2
最少要加两朵莲花,位置如 x 所示:
        0 0 0 1 0 0 0 0          0 0 0 1 0 0 0 0 
        0 x 0 0 0 2 0 1          0 0 0 0 0 2 0 1 
        0 0 0 0 x 4 0 0          0 0 x 0 x 4 0 0 
        3 0 0 0 0 0 1 0          3 0 0 0 0 0 1 0 
贝西至少要跳六步,两种不同的跳法如下:
        0 0 0 C 0 0 0 0          0 0 0 C 0 0 0 0 
        0 B 0 0 0 2 0 F          0 0 0 0 0 2 0 F 
        0 0 0 0 D G 0 0         0 0 B 0 D G 0 0 
        A 0 0 0 0 0 E 0          A 0 0 0 0 0 E 0      )

luogu 1606:

题目描述

FJ has installed a beautiful pond for his cows' aesthetic enjoyment and exercise.

The rectangular pond has been partitioned into square cells of M rows and N columns (1 ≤ M ≤ 30; 1 ≤ N ≤ 30). Some of the cells have astonishingly sturdy lilypads; others have rocks; the remainder are just beautiful, cool, blue water.

Bessie is practicing her ballet moves by jumping from one lilypad to another and is currently located at one of the lilypads. She wants to travel to another lilypad in the pond by jumping from one lilypad to another.

Surprising only to the uninitiated, Bessie's jumps between lilypads always appear as a chess-knight's move: one move in one direction and then two more in the orthogonal direction (or perhaps two in one direction and then one in the orthogonal direction).

Farmer John is observing Bessie's ballet drill and realizes that sometimes she might not be able to jump to her destination lilypad because intermediary lilypads are missing.

Ever thrifty, he wants to place additional lilypads so she can complete her quest (perhaps quickly, perhaps by using a large number of intermediate lilypads). Of course, lilypads cannot be placed where rocks already intrude on a cell.

Help Farmer John determine the minimum number of additional lilypads he has to place, and in how many ways he can place that minimum number.

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

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

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

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

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

输入格式

【输入】

第一行:两个用空格分开的整数:M和N

第二行到M+1行:第i+1行有N个用空格分开的整数,描述了池塘第i行的状态:

0为水,1为莲花,2为岩石,3为贝西所在的起点,4为贝西想去的终点。

输出格式

【输出】

第一行:一个整数,需要增加的最少莲花数;如果无解,输出-1。

第二行:放置这些莲花的方案数量,保证这个数字不会超过一个64位的有符号整数,

如果第一行是-1,不要输出第二行。

输入输出样例

输入 #1
4 5
1 0 0 0 0
3 0 0 0 0
0 0 2 0 0
0 0 0 4 0
输出 #1
2
3

说明/提示

【样例说明】

池塘分成四行五列,贝西的起点在第二行第一列,想去的终点在第四行第四列,池

塘里一共有三朵莲花和一块石头。

最少需要两朵莲花,有三种方式可以放置,

页6 如下X所示:

10000 10X00 10X00

30X00 30000 3000X

00200 0X200 00200

0X040 00040 00040

分析

两道题其实差不多啦,所以才放一起的

主要是建图思路

因为有0环与0边所以计数时会出错

先一遍dfs连边权为1的边,再跑就好(可能会连到重边,求方案数就不连,求路径数就连)

代码

luogu 2411

  1 /****************************
  2 User:Mandy.H.Y
  3 Language:c++
  4 Problem:
  5 Algorithm:
  6 Scores:
  7 ****************************/
  8 
  9 #include<bits/stdc++.h>
 10 #define Max(x,y) (x) > (y) ? (x) : (y)
 11 #define Min(x,y) (x) < (y) ? (x) : (y)
 12 
 13 using namespace std;
 14 
 15 const int maxn = 905;
 16 const int maxm = 810010;
 17 
 18 int n,m,s,t;
 19 int size = 0,first[maxn];
 20 int a[35][35],vis[maxn],id[35][35];
 21 int dis[maxn],step[maxn];
 22 long long cnt[maxn];//我还能说些什么??不开long long 见祖宗 
 23 int dx[] = {1,1,-1,-1,2,2,-2,-2};
 24 int dy[] = {2,-2,2,-2,1,-1,1,-1};
 25 
 26 struct Edge{
 27     int v,nt,w;
 28 }edge[maxm << 1];
 29 
 30 template<class T>inline void read(T &x){
 31     x = 0;bool flag = 0;char ch = getchar();
 32     while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
 33     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
 34     if(flag) x = -x;
 35 }
 36 
 37 template<class T>void putch(const T x){
 38     if(x > 9) putch(x / 10);
 39     putchar(x % 10 | 48);
 40 }
 41 
 42 template<class T>void put(const T x){
 43     if(x < 0) putchar('-'),putch(-x);
 44     else putch(x);
 45 }
 46 
 47 void file(){
 48     freopen("testdata(1).in","r",stdin);
 49 //    freopen("2411.out","w",stdout);
 50 }
 51 
 52 void eadd(int u,int v,int w){
 53     edge[ ++ size].v = v;
 54     edge[size].w = w;
 55     edge[size].nt = first[u];
 56     first[u] = size;
 57 }
 58 
 59 int getid(int x,int y){
 60     return (x - 1) * m + y;
 61 }
 62 
 63 void dfs(int x,int y,int cur,int dep){
 64     vis[id[x][y]] = 1;
 65     for(int i = 0;i < 8; ++ i){
 66         int nx = x + dx[i];
 67         int ny = y + dy[i];
 68         if(nx < 1 || ny < 1 || nx > n || ny > m) continue;
 69         if(a[nx][ny] == 2 || vis[id[nx][ny]]) continue;
 70         if(a[nx][ny] == 1) dfs(nx,ny,cur,dep + 1);
 71         else eadd(cur,id[nx][ny],dep);
 72     }
 73     vis[id[x][y]] = 0; //这一次求的是路径数,只要去掉环,其他的重合路径是需要算上的 
 74 }
 75 
 76 void readdata(){
 77     read(n);read(m);
 78     
 79     for(int i = 1;i <= n; ++ i)
 80         for(int j = 1;j <= m; ++ j){
 81             read(a[i][j]);
 82             id[i][j] = getid(i,j);
 83             if(a[i][j] == 3) s = id[i][j];
 84             if(a[i][j] == 4) t = id[i][j];
 85         }
 86 }
 87 
 88 bool SPFA(){
 89     memset(vis,0,sizeof(vis));
 90     memset(dis,0x3f3f3f3f,sizeof(dis));
 91     memset(step,0x3f3f3f3f,sizeof(step));
 92     queue<int>q;q.push(s);
 93     dis[s] = 0;step[s] = 0;cnt[s] = 1;//初始化 
 94     
 95     while( ! q.empty()){
 96         int u = q.front();
 97         q.pop();
 98         vis[u] = 0;
 99         for(int i = first[u];i;i = edge[i].nt){
100             int v = edge[i].v;
101             int w = edge[i].w;
102             if(dis[u] + 1 < dis[v]){
103                 cnt[v] = cnt[u];
104                 step[v] = step[u] + w;
105                 dis[v] = dis[u] + 1;
106                 if(! vis[v]) q.push(v),vis[v] = 1;
107             }else if(dis[u] + 1 == dis[v]){
108                 if(step[v] > step[u] + w){
109                     step[v] = step[u] + w;
110                     cnt[v] = cnt[u];
111                     if(! vis[v]) q.push(v),vis[v] = 1;
112                 }else if(step[v] == step[u] + w){
113                     cnt[v] += cnt[u];
114                     if(! vis[v]) q.push(v),vis[v] = 1;
115                 }
116                 
117             }
118         }
119     }
120     
121     if(dis[t] != 0x3f3f3f3f) return 1;
122     else return 0;
123 }
124 
125 void work(){
126         
127     for(int i = 1;i <= n; ++ i){
128         for(int j = 1;j <= m; ++ j){
129             if(a[i][j] == 2 || a[i][j] == 4) continue;
130             memset(vis,0,sizeof(vis));
131             dfs(i,j,id[i][j],1);
132         }
133     }
134     
135     if(SPFA()) {
136         put(dis[t] - 1);puts("");//    -1是为了去掉在终点放的莲花 
137         put(step[t]);puts("");
138         put(cnt[t]);puts("");
139         
140     }else{
141         puts("-1");
142     }
143     
144 }
145 
146 int main(){
147 //    file();
148     readdata();
149     work();
150     return 0;
151 }
luogu 2411

luogu 1606

  1 /**************************
  2 User:Mandy.H.Y
  3 Language:c++
  4 Problem:luogu1606
  5 Algorithm:
  6 Date:2019.7.30
  7 **************************/
  8 //最短路计数似乎用SPFA比DIjkstra快
  9 //这道题有 0 权和 0 环,如何避免
 10 //题目要求的是摆放莲花的方案数,而不是路径数
 11 //建边的时候把这个点与他距离为1的点相连 
 12 //听说两遍BFS也行,下次试试Dijkstra 
 13 #include<bits/stdc++.h>
 14 
 15 using namespace std;
 16 
 17 const int maxn = 35; 
 18 const int maxm = 810005; 
 19 
 20 int n,m,size,s,t;
 21 int a[maxn][maxn],dis[maxn * maxn],first[maxn * maxn],id[maxn][maxn];
 22 long long cnt[maxn * maxn];
 23 bool vis[maxn][maxn],used[maxn * maxn];
 24 
 25 int dx[] = {1,1,-1,-1,2,2,-2,-2};
 26 int dy[] = {2,-2,-2,2,1,-1,-1,1};
 27 
 28 struct Edge{
 29     int v,nt;
 30 }edge[maxm];
 31 
 32 template<class T>inline void read(T &x){
 33     x = 0;bool flag = 0;char ch = getchar();
 34     while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
 35     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
 36     if(flag) x = -x;
 37 }
 38 
 39 template<class T>void putch(const T x){
 40     if(x > 9) putch(x / 10);
 41     putchar(x % 10 | 48);
 42 }
 43 
 44 template<class T>void put(const T x){
 45     if(x < 0) putchar('-'),putch(-x);
 46     else putch(x);
 47 }
 48 
 49 void file(){
 50     freopen("testdata.in","r",stdin);
 51 //    freopen("pond.out","w",stdout);
 52 }
 53 
 54 void readdata(){    
 55     read(n);read(m);
 56     for(int i = 1;i <= n; ++ i)
 57         for(int j = 1;j <= m; ++ j){
 58             read(a[i][j]);
 59             if(a[i][j] == 3) s = (i - 1) * m + j;
 60             else if(a[i][j] == 4) t = (i - 1) * m + j;
 61         }
 62 }
 63 
 64 void eadd(int u,int v){
 65     edge[ ++ size].v = v;
 66     edge[size].nt = first[u];
 67     first[u] = size;
 68 }
 69 
 70 void add(int u,int x,int y){
 71     
 72     vis[x][y] = 1;//标记 
 73     
 74     for(int i = 0;i < 8; ++ i){
 75         int nx = x + dx[i];
 76         int ny = y + dy[i];
 77         
 78         if(nx < 1 || nx > n || ny < 1 || ny > m) continue;
 79         if(a[nx][ny] == 2 || vis[nx][ny]) continue;
 80         if(a[nx][ny] == 1) add(u,nx,ny);
 81         else eadd(u,id[nx][ny]),vis[nx][ny] = 1;//标记,不能连重边 因为是求方案数
 82     }
 83 }
 84 
 85 bool SPFA(){
 86     memset(dis,0x3f3f3f3f,sizeof(dis));
 87     dis[s] = 0;
 88     cnt[s] = 1;
 89     queue<int>q;
 90     q.push(s);
 91     
 92     while(!q.empty()){
 93         int u = q.front();
 94         q.pop();
 95         used[u] = 0;
 96         
 97         for(int i = first[u];i;i = edge[i].nt){
 98             int v = edge[i].v;
 99             
100             if(dis[v] > dis[u] + 1){
101                 dis[v] = dis[u] + 1;
102                 cnt[v] = cnt [u];
103                 if(! used[v]) q.push(v),used[v] = 1;
104             }else if(dis[v] == dis[u] + 1){
105                 cnt[v] += cnt[u];
106                 if(! used[v]) q.push(v),used[v] = 1; //再次入队 
107             }
108                 
109         }
110     }
111     
112     if(dis[t] != 0x3f3f3f3f) return 1;
113     else return 0;
114     
115 }
116 
117 void work(){
118     
119     for(int i = 1;i <= n; ++ i)    
120         for(int j = 1;j <= m; ++ j)
121             id[i][j] = m * (i - 1) + j;
122     
123     for(int i = 1;i <= n; ++ i)    
124         for(int j = 1;j <= m; ++ j){
125             if(a[i][j] == 1 || a[i][j] == 4) continue;//可以只给起点和水连边 
126             memset(vis,0,sizeof(vis));
127             add(id[i][j],i,j);//连边 
128         }
129             
130     
131     if(SPFA()){
132         put(dis[t] - 1);
133         puts("");
134         put(cnt[t]);
135     }else{
136         puts("-1");
137     }
138 }
139 
140 int main(){
141 //    file();
142     readdata();
143     work();
144     return 0;
145 }
luogu 1606

 

posted @ 2019-09-04 15:01  Mandy_H_Y  阅读(242)  评论(0编辑  收藏  举报