[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;
}

 

posted @ 2018-04-15 17:58  qjs12  阅读(81)  评论(0编辑  收藏  举报