题解 P2103 【道路值守】
先Floyd求出最短路
对于每一个点i:
{ 枚举所有点j ,确保i,j联通,且i,j不是一点。
然后检查有多少点k与j有连边,且在i-j的最短路dis[i][j]上。(也就是检查从i到j有多少条边满足在dis[i][j]上且与j相连)
esum[j]=1*k , k∈(g[k][j]!=0 && dis[i][k]+g[k][j]==dis[i][j])
最后考虑DP
枚举一个终点j,再枚举一个k,如果k在i-j的最短路上,那么esum[k]个方案计入C[i][j]。(有esum[k]条边可以到k点,在最短路上可以选k点,所以要计入方案数目)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<iterator>
#include<utility>
#include<queue>
using namespace std;
int nodenum,edgenum;
int g[510][510]={0},dis[510][510]={0},fx,wx,tx,C[510][510]={0};
int esum[510]={0};
inline void readx(int& x)
{
x=0;
register char ch=0; int k=1;
while (ch<'0' || ch>'9') { ch=getchar(); if (ch=='-') k=-1; }
while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
x*=k;
}
void SPFA(int nodex)
{
bool vis[510]={0};
register int prex,u,v;
queue<int> que;
vis[nodex]=true; dis[nodex][nodex]=0; que.push(nodex);
while (!que.empty())
{
u=que.front(); que.pop();
vis[u]=false;
for (register int i=1;i<=nodenum;i++) if (g[u][i])
{
if (dis[nodex][i]>dis[nodex][u]+g[u][i])
{
dis[nodex][i]=dis[nodex][u]+g[u][i];
if (!vis[i])
{
que.push(i);
vis[i]=true;
}
}
}
}
}
int main()
{
memset(dis,0x3f,sizeof(dis));
readx(nodenum); readx(edgenum);
for (register int i=1;i<=edgenum;i++)
{
readx(fx); readx(tx); readx(wx);
g[fx][tx]=g[tx][fx]=wx;
}
for (register int i=1;i<=nodenum;i++) SPFA(i);
//init
for (register int i=1;i<=nodenum;i++)
{
memset(esum,0,sizeof(esum));
for (register int j=1;j<=nodenum;j++) if (i!=j && dis[i][j]!=dis[0][0])
{
for (register int k=1;k<=nodenum;k++) if (g[k][j])
{
if (dis[i][k]+g[k][j]==dis[i][j]) esum[j]++;
}
}
for (register int j=1;j<=nodenum;j++) if (i!=j)
{
for (register int k=1;k<=nodenum;k++) if (i!=k)
{
if (dis[i][k]+dis[k][j]==dis[i][j]) C[i][j]+=esum[k];
}
}
}
for (register int i=1;i<=nodenum;i++)
for (register int j=i+1;j<=nodenum;j++) printf("%d ",C[i][j]);
return 0;
}
}