RE心态爆炸,在欢声笑语中打出了GG
题意:给出一个有向图,删去图中的某些边(可以不删),使剩下的边构成一棵树,且0号点到每个点的距离依然为原图中0号点到每个点的最短距离。
思路:SPFA处理出0号点到所有点的最小距离,保留只含最短路的有向无环图,处理每个点的入度,每个点任意选择一个入边即可,所以答案是每个点的入度相乘。
一直都忽略了有向这个条件,思考出错,经常没有记好题目的条件,想着想着就变另一题了。。。gg
#include <set>
#include <cmath>
#include <queue>
#include <string>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=2505;
const int INF=1e9+7;
const ll mod=1e9+7;
#define pb push_back
#define fi first
#define se second
#define mp mak_pair
#define pii pair<int,int>
int last[N],dis[N],ct[N],s[N][N];
int cnt=0;
void init() {
cnt=0;
memset(last,-1,sizeof last);
}
struct edge {
int to,pre,cost;
}es[2*N];
bool vis[N];
void addEdge(int u,int v,int w) {
edge e={v,last[u],w};
es[++cnt]=e;
last[u]=cnt;
}
void SPFA(int s,int n) {
memset(vis,false,sizeof vis);
for(int i=1;i<=n;++i) dis[i]=INF;
vis[s]=true;
dis[s]=0;
queue<int> que;
while(!que.empty()) que.pop();
que.push(s);
while(!que.empty()) {
int u=que.front(); que.pop();
vis[u]=false;
for(int i=last[u];i!=-1;i=es[i].pre) {
int v=es[i].to;
if(dis[u]+es[i].cost<dis[v]) {
dis[v]=dis[u]+es[i].cost;
if(!vis[v]) {
vis[v]=true;
que.push(v);
}
}
}
}
}
int main() {
int n;
char x;
while(~scanf("%d",&n)) {
init();
memset(ct,0,sizeof ct);
for(int i=1;i<=n;++i) {
getchar();
for(int j=1;j<=n;++j) {
scanf("%c",&x);
s[i][j]=x-'0';
if(x!='0') addEdge(i,j,x-'0');
}
}
SPFA(1,n);
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j) {
if(s[j][i] && dis[j]+s[j][i]==dis[i]) ++ct[i];
}
ll ans=1;
for(int i=1;i<=n;++i) if(ct[i]) ans=ans*1ll*ct[i]%mod;
printf("%I64d\n",ans%mod);
}
return 0;
}