[HAOI2012] 道路
这道题目我是80分,T了两个点,因为最后的每次路径统计我用的是 O( n2 ) 的暴力统计,好像即使 O ( n ) 我的算法理论也跑不过,原本以为只能拿60,结果只T了两个点,弄得我不想改了,改的话应该用一个类似树规,记忆化的方式吧。
这题依旧考最短路树,我的方法是暴力以每个点为起点跑dijstra,然后在dfs过程中只走 dis[v] == dis[u] + e.val 的边走,对应 e 的重要度加上以 v 为根的子树大小,因为到那些所有点都要经过这条边,复杂度 O ( n4logm ) ? 我不会算,反正写的时候我也没算......
也有可能我的方法本来就是暴力......怎么可能是正解......
突然想到我听说过暴力80,正解被卡常剩20的惊天劈地的说法,而且义正言辞。
正解被卡常剩20,那这个正解真的比我女神要正多了。
不知道这两个成语用的对不对。
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; const int M=5000+10,INF=(int)1e9,mod=1000000007; int n,m,cnt,head[M],dis[M],ans[M],size[M]; bool done[M],vis[M]; struct Edge { int u,v,w,next; Edge():u(0),v(0),w(0),next(-1){}; }ed[M<<1]; struct Node { int u,w; bool operator < (const Node &A) const { return w>A.w; } }; void add_edge(int a,int b,int c) { ed[++cnt].u=a,ed[cnt].v=b,ed[cnt].w=c,ed[cnt].next=head[a],head[a]=cnt; } void dfs(int u) { size[u]=1; for(int i=head[u];i!=-1;i=ed[i].next) { Edge p=ed[i]; if(!vis[p.v]&&dis[p.v]==dis[p.u]+p.w) { vis[p.v]=true; dfs(p.v); size[p.u]+=size[p.v]; ans[i]=(ans[i]+size[p.v])%mod; vis[p.v]=false; } } } void dijstra(int s) { for(int i=1;i<=n;i++) dis[i]=INF,done[i]=false; dis[s]=0; priority_queue<Node> q; q.push((Node){s,dis[s]}); while(!q.empty()) { Node x=q.top(); q.pop(); if(done[x.u]) continue; done[x.u]=true; for(int i=head[x.u];i!=-1;i=ed[i].next) { Edge p=ed[i]; if(dis[p.u]+p.w<dis[p.v]) { dis[p.v]=dis[p.u]+p.w; q.push((Node){p.v,dis[p.v]}); } } } memset(size,0,sizeof(size)); vis[s]=true; dfs(s); vis[s]=false; } int main() { freopen("roadsw.in","r",stdin); freopen("roadsw.out","w",stdout); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); int a,b,c; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add_edge(a,b,c); } for(int i=1;i<=n;i++) dijstra(i); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }