hdu6026 Deleting Edges(最短路+计数)

思路来源

https://blog.csdn.net/mengxiang000000/article/details/72801224

题意

n个点,输入它的邻接矩阵形式,注意0是没有边,其余对应数为其权值。

求删边方案数,使得删完边之后是一颗生成树,且所有点到0号点的最短路是不删边之前的最短路。

n<=50(数据好弱的说)

题解

先dijkstra跑一遍最短路,然后开始统计对任意一个节点,其最短路径的条数。

注意到,若出现dis[v]==dis[u]+w时,说明出现路径相同的两条,但该长度可能不是最短路。

所以我们每次dis[v]>dis[u]+w更新最短路时,就将in[]数组置0,

之后每次相同就++,统计除当前最短外还有相同长度路径的条数。

最后ans=每个路径的最短路条数之积,即\prod_{i=1}^{n-1}in[i]+1

注意到一棵生成树只差一个点时,若一个点能从已知树上点与该树建边,则树上已存点和该点的父子关系是确定的。

树上最短路是恒定的,说明若dis[v]==dis[u]+w时,dis[u]是不可能dis[v]+w的,

所以一条边最多只对一个点的最短路径有贡献,我们模拟点的插入过程,

统计每个点到树的最短路路径条数,即每个点到最短路树的出度即可。

心得

ans=每个路径的最短路条数之积这个想了很久,

后来才发现,树上最短路的关系不是相对的,即已知最短路只能扩展到其儿子。

我们在统计一个点的时候,将当前树形固定下来即可。

代码

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10; 
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<double,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int head[1005],cnt,n,in[1005],dis[1005];
char tmp[1005];
bool vis[1005]; 
struct edge{int to,nex,w;}e[1<<20];
priority_queue<pii,vector<pii>,greater<pii> >q;
void init()
{
	cnt=0;
	mem(dis,INF);
	mem(head,-1);
	mem(vis,0);
	mem(in,0);
}
void add(int u,int v,double w)
{
	e[cnt].to=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt++;
}
void dijkstra(int u)
{
	dis[u]=0;
	q.push(pii(0,0));
	while(!q.empty())
	{
		pii tmp=q.top();
		q.pop();
		int fi=tmp.first,se=tmp.second;
		if(vis[se])continue;
		vis[se]=1;
		for(int i=head[se];~i;i=e[i].nex)
		{
			int v=e[i].to,w=e[i].w;
			if(dis[v]>dis[se]+w)
			{
				dis[v]=dis[se]+w;
				q.push(pii(dis[v],v));
				in[v]=0;
			}
			else if(dis[v]==dis[se]+w)
			{
				in[v]++;
			}
		}
	}
}
int main()
{ 
    while(~scanf("%d",&n))
    {
    	init();
    	rep(i,0,n-1)
    	{
    		scanf("%s",tmp);
    		rep(j,0,n-1)
    		{
    			if(tmp[j]=='0')continue;
    			else add(i,j,tmp[j]-'0');
    		}
    	}
    	dijkstra(0);
    	ll ans=1;
    	rep(i,1,n-1)
		{
		 ans*=(1+in[i]);
		 if(ans>=mod)ans%=mod;
	    }
    	printf("%lld\n",ans);
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/83785658