P2176 [USACO14FEB]路障Roadblock
题目描述
每天早晨,FJ从家中穿过农场走到牛棚。农场由 N 块农田组成,农田通过 M 条双向道路连接,每条路有一定长度。FJ 的房子在 1 号田,牛棚在 N 号田。没有两块田被多条道路连接,以适当的路径顺序总是能在农场任意一对田间行走。当FZ从一块田走到另一块时,总是以总路长最短的道路顺序来走。
FJ 的牛呢,总是不安好心,决定干扰他每天早晨的计划。它们在 M 条路的某一条上安放一叠稻草堆,使这条路的长度加倍。牛希望选择一条路干扰使得FJ 从家到牛棚的路长增加最多。它们请你设计并告诉它们最大增量是多少。
输入输出格式
输入格式:
第 1 行:两个整数 N, M。
第 2 到 M+1 行:第 i+1 行包含三个整数 A_i, B_i, L_i,A_i 和 B_i 表示道路 i 连接的田的编号,L_i 表示路长。
输出格式:
第 1 行:一个整数,表示通过使某条路加倍而得到的最大增量。
输入输出样例
输入样例#1:
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
输出样例#1:
2
说明
【样例说明】
若使 3 和 4 之间的道路长加倍,最短路将由 1-3-4-5 变为 1-3-5。
【数据规模和约定】
对于 30%的数据,N <= 70,M <= 1,500。
对于 100%的数据,1 <= N <= 100,1 <= M <= 5,000,1 <= L_i <= 1,000,000。
题目大意:求将1--n上最短路的某条边的边权*2后新的最短路与原最短路长度差最大是多少
题解:暴力枚举最短路的每一条边*2再跑最短路取max
代码:
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; queue<int>q; int n,m,sumedge,cnt,cur,ans; int head[110],pre[110],cut[1100],bege[1100],dis[110],inq[110]; struct Edge{ int x,y,z,nxt; Edge(int x=0,int y=0,int z=0,int nxt=0): x(x),y(y),z(z),nxt(nxt){} }edge[5002*2]; void add(int x,int y,int z){ edge[++sumedge]=Edge(x,y,z,head[x]); head[x]=sumedge; } int spfa(){ memset(dis,127/3,sizeof(dis)); memset(inq,0,sizeof(inq)); while(!q.empty())q.pop(); q.push(1);dis[1]=0;inq[1]=1; while(!q.empty()){ int now=q.front();q.pop();inq[now]=0; for(int i=head[now];i;i=edge[i].nxt){ int v=edge[i].y; if(dis[v]>dis[now]+edge[i].z){ dis[v]=dis[now]+edge[i].z; pre[v]=now;bege[v]=i; if(!inq[v]){ inq[v]=1; q.push(v); } } } } return dis[n]; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z);add(y,x,z); } cur=spfa(); // cout<<dis[3]<<" "<<dis[4]<<endl; for(int i=n;i;i=pre[i]) cut[++cnt]=bege[i]; for(int i=1;i<=cnt;i++){ int k=cut[i]; // cout<<k<<endl; if(k&1){ edge[k].z*=2; edge[k+1].z*=2; }else { edge[k].z*=2; edge[k-1].z*=2; } ans=max(ans,spfa()); if(k&1){ edge[k].z/=2; edge[k+1].z/=2; }else{ edge[k].z/=2; edge[k-1].z/=2; } } // cout<<ans<<" "<<cur<<endl; cout<<ans-cur<<endl; return 0; }