题解 洛谷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.
上一篇:vue使用swiper vue-awesome-swiper记录


下一篇:Check common information about Linux system