[最短路]洛谷P1606 [USACO07FEB]Lilypad Pond G
一道建图 毒瘤 好题。 传送门
题目上不是很像建图,但是想到建图并不是很难。
这一手把通往荷花的路权值记为 \(0\) ,把通往水的边权值记为 \(1\) 。 直接上 dijkstra , 20min 写完 die 码。
#include <bits/stdc++.h>
#define debug puts("I ak IOI several times");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
t=0; register char ch=getchar(); register int fflag=1;
while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
while(('0'<=ch&&ch<='9')){t=((t<<1)+(t<<3))+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){
read(t);read(args...);
}
template <typename T>inline void write(T x){
if(x<0) putchar('-'),x=~(x-1); int s[40],top=0;
while(x) s[++top]=x%10,x/=10; if(!top) s[++top]=0;
while(top) putchar(s[top--]+'0');
}
const int MAXN=45*45,MAXM=10000000,inf=0x3f3f3f3f;
struct Edge{
int to,val,nxt;
}e[MAXM];
struct Node{
int to,val;
bool operator < (const Node &node) const{
return val>node.val;
}
};
priority_queue<Node>Q;
bool vis[MAXN];
int head[MAXN],cnt,n,m,_mp[50][50],sta,en,dis[MAXN],way[MAXN];
const int dx[]={1,1,-1,-1,2,2,-2,-2},
dy[]={2,-2,2,-2,1,-1,1,-1};
inline int Num(int x,int y){return (x-1)*m+y;}
void add(int x,int y,int val){
e[++cnt]={y,val,head[x]};
head[x]=cnt;
return;
}
void ADD(int x,int y){
if(_mp[x][y]==3) sta=Num(x,y);
if(_mp[x][y]==4) en=Num(x,y);
for(int i=0;i<8;++i){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||ny<1||nx>n||ny>m) continue;
if(_mp[nx][ny]!=2){
if(_mp[nx][ny]==1||_mp[nx][ny]==4) add(Num(x,y),Num(nx,ny),0);
if(_mp[nx][ny]==0) add(Num(x,y),Num(nx,ny),1);
}
}
}
void intt(){
read(n,m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
read(_mp[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
ADD(i,j);
}
void dijk(){
intt();
memset(dis,0x3f,sizeof(dis));
memset(way,0,sizeof(way));
dis[sta]=0; Q.push({sta,0});
way[sta]=1;
while(!Q.empty()){
int u=Q.top().to; Q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]>dis[u]+e[i].val&&!vis[v]){
dis[v]=dis[u]+e[i].val;
way[v]=way[u];
Q.push({v,dis[v]});
}else if(dis[v]==dis[u]+e[i].val) way[v]+=way[u];
}
}
if(!way[en]) cout<<-1<<endl;
else cout<<dis[en]<<endl<<way[en]<<endl;
return;
}
int main(){
dijk();
return 0;
}
//Welcome back,Chtholly.
50pts ,查看一手错误信息,第二行的问题。
什么问题呢,反手查看题解,发现。题目并不是问的最短路的条数,而是问有多少种放置荷花的方式。
那么怎么办呢,就用 dfs 建边,只对于水、起点建边,然后如果是荷花,那么把它看成上一个水,建边建在水上,而不是荷花上。
再加上亿点点细节。
#include <bits/stdc++.h>
#define debug puts("I ak IOI several times");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
t=0; register char ch=getchar(); register int fflag=1;
while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
while(('0'<=ch&&ch<='9')){t=((t<<1)+(t<<3))+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){
read(t);read(args...);
}
template <typename T>inline void write(T x){
if(x<0) putchar('-'),x=~(x-1); int s[40],top=0;
while(x) s[++top]=x%10,x/=10; if(!top) s[++top]=0;
while(top) putchar(s[top--]+'0');
}
const int MAXN=51*51,MAXM=10000000,inf=0x3f3f3f3f;
struct Edge{
int to,val,nxt;
}e[MAXM];
struct Node{
int to,val;
bool operator < (const Node &node) const{
return val>node.val;
}
};
priority_queue<Node>Q;
bool vis[MAXN],visi[MAXN][MAXN];
int head[MAXN],cnt,n,m,_mp[50][50],sta,en,dis[MAXN];
long long way[MAXN];
const int dx[]={1,1,-1,-1,2,2,-2,-2},
dy[]={2,-2,2,-2,1,-1,1,-1};
inline int Num(int x,int y){return (x-1)*m+y;}
void add(int x,int y,int val){;
e[++cnt]={y,val,head[x]};
head[x]=cnt;
return;
}
void dfs(int x,int y,int num){
visi[x][y]=1;
for(int i=0;i<8;++i){
int nx=dx[i]+x,ny=dy[i]+y;
if(visi[nx][ny]||_mp[nx][ny]==2||nx<1||ny<1||nx>n||ny>m) continue;
if(_mp[nx][ny]==1) dfs(nx,ny,num);
else visi[nx][ny]=1,add(num,Num(nx,ny),1);
}
}
void ADD(int x,int y){
if(_mp[x][y]==3) sta=Num(x,y);
if(_mp[x][y]==4) en=Num(x,y);
if(_mp[x][y]==0||_mp[x][y]==3||_mp[x][y]==4){
memset(visi,0,sizeof(visi));
dfs(x,y,Num(x,y));
}
return;
}
void intt(){
read(n,m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
read(_mp[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
ADD(i,j);
}
void dijk(){
intt();
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(way,0,sizeof(way));
dis[sta]=0; Q.push({sta,0});
way[sta]=1;
while(!Q.empty()){
int u=Q.top().to; Q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]>dis[u]+e[i].val){
dis[v]=dis[u]+e[i].val;
way[v]=way[u];
Q.push({v,dis[v]});
}else if(dis[v]==dis[u]+e[i].val) way[v]+=way[u];
}
}
if(!way[en]) cout<<-1<<endl;
else cout<<dis[en]-1<<endl<<way[en]<<endl;
return;
}
signed main(){
dijk();
return 0;
}
//Welcome back,Chtholly.