标签:class har while cstring 森林 san 多次 names max
考试的时候我没有想到动态加点,暴力跑了n遍dijstra,用dis[i][j][k]表示i,j之间经过的点权最大的点为k时的最短路径,这样会重复更新很多次,所以T了
Solution
类似魔法森林,按照点权值从小到大动态加点进去跑dijstra什么的,保证当前更新答案的时候,最大点权为当前加进去的点的点权,spfa好像要被卡(完全图),也可以按
照点权顺序枚举k跑floyed,注意更新答案的时候即使dis没有被更新过也需要更新一下
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> using namespace std; typedef long long lo; const int nn=511,mm=2511,din=1061109567; const lo inf=4557430888798830399; lo res[nn][nn]; int dis[nn][nn],dw[nn],th[nn]; int read() { int ans=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} while(isdigit(ch)) {ans=ans*10+ch-‘0‘;ch=getchar();} return ans*f; } int cmp(const int a,const int b) { return dw[a]<dw[b]; } int main() { freopen("path.in","r",stdin); freopen("path.out","w",stdout); int n,m,u,v,w;lo zc; memset(dis,0x3f3f3f,sizeof(dis)); memset(res,0x3f3f3f,sizeof(res)); n=read();m=read(); for(int i=1;i<=n;i++) dw[i]=read(),th[i]=i; for(int i=1;i<=m;i++) u=read(),v=read(),w=read(),dis[u][v]=dis[v][u]=w,res[u][v]=res[v][u]=(lo)w*max((lo)dw[u],(lo)dw[v]); sort(th+1,th+n+1,cmp); for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(dis[i][j]>max(dis[i][th[k]],dis[th[k]][j])) { dis[i][j]=max(dis[i][th[k]],dis[th[k]][j]); } } for(int i=1;i<=n;i++) //不一定要更新dis之后才更新res for(int j=1;j<=n;j++) if(dw[i]<=dw[th[k]]&&dw[j]<=dw[th[k]]&&dis[i][j]!=din) { zc=(lo)dis[i][j]*(lo)dw[th[k]]; if(zc<res[i][j]) res[i][j]=zc; } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) if(i==j) printf("0 "); else if(res[i][j]==inf) printf("-1 "); else printf("%lld ",res[i][j]); //d/lld printf("\n"); } return 0; }
标签:class har while cstring 森林 san 多次 names max
原文地址:http://www.cnblogs.com/charlotte-o/p/7682601.html