NKOJ 4284 路径数【最短路计数】

在这里插入图片描述

我们把对角线下面的权值放到上面,然后将对角线上任意一点作为终点。

然后最短路计数一下就好了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const ll N=2e2+5;
const ll Inf=1e18;
const ll Mod=1e9+9;

ll n,t,mp[N][N],id[N][N];
ll dis[N*N],vis[N*N],tot[N*N];
ll cnt,to[N*N],edge[N*N],nxt[N*N],head[N*N];

ll dx[4]={0,0,-1,1};
ll dy[4]={1,-1,0,0};

struct node {
	ll num,dis;
	bool operator < (const node &a) const {
		return a.dis<dis;
	}
};

inline ll add(ll x,ll y) {
	return x+y>=Mod?x+y-Mod:x+y;
}

bool check(ll x,ll y) {
	return 1<=x&&x<=n&&1<=y&&y<=n;
}

void ins(ll x,ll y,ll z) {
	to[++cnt]=y;edge[cnt]=z;nxt[cnt]=head[x];head[x]=cnt;
}

void dij(ll s) {
	priority_queue<node>pq;
	for(ll i=1;i<=n*n;i++) dis[i]=Inf,vis[i]=tot[i]=0;
	dis[s]=0;tot[s]=1;node tmp;tmp.num=s;pq.push(tmp);
	
	while(pq.size()) {
		ll x=pq.top().num;pq.pop();
		
		if(!vis[x]) {
			vis[x]=1;
			for(ll i=head[x];i;i=nxt[i]) {
				ll y=to[i],z=edge[i];
				
				if(dis[y]>dis[x]+z) {
					dis[y]=dis[x]+z;tot[y]=tot[x];
					tmp.num=y;tmp.dis=dis[y];pq.push(tmp);
				} else if (dis[y]==dis[x]+z) tot[y]=add(tot[y],tot[x]);
			}
		}
	}
}

int main() {
	while(~scanf("%lld",&n)) {
		if(n==0) return 0;
		
		cnt=t=0;memset(head,0,sizeof(head));
		
		for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) scanf("%lld",&mp[i][j]);
		
		for(ll i=1;i<n;i++) for(ll j=1;j<=n-i;j++) mp[i][j]=add(mp[i][j],mp[n+1-j][n+1-i]);
		
		for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) id[i][j]=++t;
		
		for(ll i=1;i<n;i++) for(ll j=1;j<=n-i;j++) {
			for(ll k=0;k<=3;k++) if(check(i+dx[k],j+dy[k])) {
				ins(id[i][j],id[i+dx[k]][j+dy[k]],mp[i+dx[k]][j+dy[k]]);
			}
		}
		
		dij(1);
		
		ll ans=Inf,num=0;
		
		for(ll i=1;i<=n;i++) {
			if(dis[id[i][n+1-i]]<ans) {
				ans=dis[id[i][n+1-i]];num=tot[id[i][n+1-i]];
			} else if (dis[id[i][n+1-i]]==ans) num+=tot[id[i][n+1-i]];
		}
		
		printf("%lld\n",num);
	}
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/83513616