1. 程式人生 > >luoguP1606 [USACO07FEB]荷葉塘Lilypad Pond--最短路計數

luoguP1606 [USACO07FEB]荷葉塘Lilypad Pond--最短路計數

題目大意:新增最少石頭的方案數。

一種樸素的想法是是每個節點向外建邊,是荷花建0邊,新增建1邊,然後跑最短路計數,這樣只能得部分分。為什麼呢?比如可以多個荷花節點向同一個水節點建邊,實際是一種放置石頭得方案,但這樣就會統計成多種。 因此正確得建圖方法是一個荷花聯通塊,新增一個石頭可以到達哪裡。,然後再統計最短路條數就是不同得方案數了。

建圖抄了dfs的,又寫了個bfs的。原理是一樣的。

參考程式碼:

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=31,inf=0x3f3f3f3f;
const int fx[8][2]= {2,-1,2,1,-2,-1,-2,1,1,2,-1,2,1,-2,-1,-2};

struct node {
	int to,next;
} e[500010];
int cnt,head[N*N];
void add(int u,int v) {
	e[++cnt].to=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int mp[N][N],dis[N*N],p[N][N],inq[N*N],n,m;
LL f[N*N];
bool vis[N][N];
void dfs(int po,int x,int y) {//dfs建邊。 
	vis[x][y]=1;
	for(int i=0; i<8; i++) {
		int dx=x+fx[i][0],dy=y+fx[i][1];
		if(dx<1 || dy<1 || dx>n || dy>m || vis[dx][dy])continue;
		if(mp[dx][dy]==1)dfs(po,dx,dy);//這個點是花,直接跳過去。
		else vis[dx][dy]=1,add(po,p[dx][dy]);//這個點不是花,加一個花
	}
}
void bfs(int po,int x,int y) { //bfs建邊,處理荷葉聯通塊,荷葉直接進佇列,向水或終點建邊。 
	queue<int>qx,qy;
	qx.push(x),qy.push(y);
	vis[x][y]=1;//進過佇列不再進佇列 
	while(!qx.empty()) {
		int x=qx.front(),y=qy.front();
		qx.pop(),qy.pop();
		for(int i=0; i<8; i++) {
			int dx=x+fx[i][0],dy=y+fx[i][1];
			if(dx<1 || dy<1 || dx>n || dy>m || vis[dx][dy])continue;
			vis[dx][dy]=1;
			if(mp[dx][dy]==1)qx.push(dx),qy.push(dy);//
			else if(mp[dx][dy]!=2)add(po,p[dx][dy]);
		}
	}
}
queue<int>q;
int main() {
	int i,j,x,y,k,st,ed;
	cin>>n>>m;
	for(i=1; i<=n; i++)
		for(j=1; j<=m; j++)p[i][j]=(i-1)*m+j;
	for(i=1; i<=n; i++)
		for(j=1; j<=m; j++) {
			cin>>mp[i][j];
			if(mp[i][j]==3)st=p[i][j];
			if(mp[i][j]==4)ed=p[i][j];

		}
	for(i=1; i<=n; i++)
		for(j=1; j<=m; j++)
			if(mp[i][j]!=2) {
				memset(vis,0,sizeof(vis));
				bfs(p[i][j],i,j);
			}
	memset(dis,127,sizeof(dis));
	memset(inq,0,sizeof(inq));
	dis[st]=0,inq[st]=1;
	f[st]=1;
	q.push(st);
	while(!q.empty()) {
		int v,u=q.front();
		q.pop();
		inq[u]=0;
		for(int i=head[u]; i; i=e[i].next) {
			v=e[i].to;
			if(dis[v]>dis[u]+1) {
				dis[v]=dis[u]+1,f[v]=f[u];
				if(!inq[v]) {
					inq[v]=1;
					q.push(v);
				}
			} else if(dis[v]==dis[u]+1)
				f[v]+=f[u];
		}
	}
	if(dis[ed]<inf)printf("%d\n%lld\n",dis[ed]-1,f[ed]);
	else printf("-1\n");
	return 0;
}