标签:NPU color 编号 路径 复制 额外 shortcut freopen 相同
USACO 19年一月月赛金组第三题
每天晚上,Farmer John都会敲响一个巨大的铃铛,召唤他的奶牛们前来牛棚享用晚餐。奶牛们都急切地想要前往牛棚,所以她们都会沿着最短的路径行走。 农场可以描述为N块草地(1≤N≤10,000),方便起见编号为1…N,牛棚位于草地1。草地之间由M条双向的小路连接(N−1≤M≤50,000)。每条小路有其通过时间,从每块草地出发都存在一条由一些小路组成的路径可以到达牛棚。
草地i中有ci头奶牛。当她们听到晚餐铃时,这些奶牛都沿着一条消耗最少时间的路径前往牛棚。如果有多条路径并列消耗时间最少,奶牛们会选择其中“字典序”最小的路径(也就是说,她们通过在两条路径第一次出现分支的位置优先选择经过编号较小的草地的方式来打破并列关系,所以经过草地7、3、6、1的路径会优先于经过7、5、1的路径,如果它们所消耗的时间相同)。
Farmer John担心牛棚距离某些草地太远。他计算了每头奶牛路上的时间,将所有奶牛消耗的时间相加,称这个和为总移动时间。他想要通过额外添加一条从牛棚(草地1)连接到某块他选择的其他草地的、通过时间为T(1≤T≤10,000)的“近道”来尽可能地减少总移动时间。当一头奶牛在她平时前往牛棚的路上偶然看见这条近道时,如果这条近道能够使她更快地到达牛棚,她就会走这条路。否则,一头奶牛会仍然沿着原来的路径行走,即使使用这条近道可能会减少她的移动时间。
请帮助Farmer John求出通过添加一条近道能够达到的总移动时间减少量的最大值。
输入的第一行包含N、M和T。以下N行包含c1…cN,均为0…10,000范围内的整数。以下M行,每行由三个整数a,b和t描述了一条小路,这条小路连接了草地a和b,通过时间为t。所有的通过时间在1…25,000范围内。
输出Farmer John可以达到的总移动时间的最大减少量。
5 6 2 1 2 3 4 5 1 2 5 1 3 3 2 4 3 3 4 5 4 5 2 3 5 7
40
#include<bits/stdc++.h> #define N 10007 #define M 50007 using namespace std; struct node{ int y,next,z; }e[M*2],E[M*2]; struct P{ int x,y,z; }a[M*2]; int n,m,t; int c[N],head[N],tot,head1[N],tot1; long long ans=0; void add(int x,int y,int z){e[++tot].y=y;e[tot].z=z;e[tot].next=head[x];head[x]=tot;} void add1(int x,int y){E[++tot1].y=y;E[tot1].next=head1[x];head1[x]=tot1;} queue<int> q; long long d[N],v[N],p[N],pre[N]; bool cmp(P i,P j){ if(i.x!=j.x) return i.x<j.x; else return i.y<j.y; } void spfa(int s){ memset(d,0x3f,sizeof(d)); q.push(s);v[s]=1;d[s]=0; while(!q.empty()){ int x=q.front();v[x]=0;q.pop(); for(int i=head[x];i;i=e[i].next){ int y=e[i].y,z=e[i].z; if(d[y]>d[x]+z){ d[y]=d[x]+z; pre[y]=x; if(!v[y]) q.push(y),v[y]=1; } else if(d[y]==d[x]+z)pre[y]=min(pre[y],(long long)x); } } } void dfs(int x,int fa){ p[x]=c[x]; for(int i=head1[x];i;i=E[i].next){ int y=E[i].y; if(y!=fa) dfs(y,x),p[x]+=p[y]; } long long g=(d[x]-t)*p[x]; ans=max(g,ans); } int main() { // freopen("shortcut.in","r",stdin); // freopen("shortcut.out","w",stdout); cin>>n>>m>>t; for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); for(int i=m+1;i<=2*m;i++) a[i].y=a[i-m].x,a[i].x=a[i-m].y,a[i].z=a[i-m].z; for(int i=2*m;i>=1;i--) add(a[i].x,a[i].y,a[i].z); spfa(1); for(int i=1;i<=n;i++) add1(i,pre[i]),add1(pre[i],i); dfs(1,0); cout<<ans<<endl; return 0; }
标签:NPU color 编号 路径 复制 额外 shortcut freopen 相同
原文地址:https://www.cnblogs.com/wangyiding2003/p/11569125.html