原本以为是给我所有点到1号点的距离,然后问我有多少棵树满足这个要求。
(一个明显是dp的dp吧)
其实差不多,但是它已经把所有能选的边给你了。
差别就是我枚举的时候多了一个要求。
所以这题就是先跑一遍单源最短路,然后把所有点按照dist排序。
以为没有负边,所以dist大的点一定是连在dist严格小与它的点上的。
而我们要找的方案数其实就是每个点x满足\(dist[x]+a[x][u]= dist[u]\)的种类数的乘积。
还是很好写也很好理解的。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
char c=getchar();ll a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,m,head[2000001],dist[1001],tot,vis[1001],d[1001],p[1001],a[1001][1001];
struct edge
{
ll next,to,v;
}e[2000001];
const ll Mod=(1LL<<31)-1;
inline void add(ll i,ll j,ll v)
{
e[++tot].next=head[i];
e[tot].to=j;
e[tot].v=v;
head[i]=tot;
}
void dijkstra()
{
priority_queue<pair<ll,ll>, vector<pair<ll,ll> >,greater<pair<ll,ll> > > q;
q.push({0,1});
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
while(!q.empty())
{
ll x=q.top().second;
q.pop();
if(vis[x]==1)continue;
vis[x]=1;
for(ll i=head[x];i!=0;i=e[i].next)
{
ll u=e[i].to;
if(dist[x]+e[i].v<dist[u])
{
dist[u]=dist[x]+e[i].v;
q.push({dist[u],u});
}
}
}
}
bool cmp(ll a,ll b)
{
return dist[a]<dist[b];
}
int main()
{
n=read(),m=read();
for(ll i=1;i<=m;i++)
{
ll x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
a[x][y]=a[y][x]=z;
}
for(ll i=1;i<=n;i++)p[i]=i;
dijkstra();
sort(p+1,p+1+n,cmp);
memset(vis,0,sizeof(vis));
memset(d,0x3f,sizeof(d));
d[1]=0;
ll ans=1;vis[1]=1;
for(ll i=2;i<=n;i++)
{
ll now=p[i];
ll cnt=0;
for(ll j=1;j<=n;j++)
{
if(vis[j]&&a[p[i]][j]!=0&&a[p[i]][j]+dist[j]==dist[p[i]])cnt++;
}
vis[p[i]]=1;
ans=ans*cnt%Mod;
}
cout<<ans<<endl;
return 0;
}
我调了很久。
因为我tm把大根堆当小根堆用。
我明明上次记过了啊,greater就是大的在上面,跟是最上面的。每次取出来的是跟!
我服了我自己了。
这题的思路。。好像对于我来说没什么要学的了。
只要注意到什么情况下能够产生其他的方案数,这题就做出来了。
其实没啥难点