最近打的一场校内训练的某题原题。。。
题目如下:
Description
公元22××年,宇宙中最普遍的交通工具是spaceship。spaceship的出现使得星系之间的联系变得更为紧密,所以spaceship船长也成了最热门的职业之一。当然,要成为一名出色的船长,必须通过严格的考核,例如下面是最简单的问题中的一个。 用1~n的整数给n个星系标号,目前你在标号为1的星系,你需要送快递到标号为n的星系,星系之间由于存在陨石带,并不是都可以直连的。同时,由于超时空隧道的存在,在某些星系间飞行会出现时间静止甚至倒流,飞行时间为0或为负数。另外,由星系i到星系j的时间和由星系j到星系i的时间不一定是相同的。 在寄出日期之前收到快递被认为是不允许的,所以每部spaceship上都有一个速度调节装置,可以调节飞行的时间。简单来说其功能就是让所有两个星系间的飞行时间(如果可以直达)都增加或减少相同的整数值,你的任务就是调整速度调节器,找出一条用最短时间完成任务的路径,并且保证这个最短时间的值大于或等于0。
INPUT
输入文件包含多组数据,第1个数为T,表示数据的数量。 对于每一组数据,输入第1行为两个正整数N(2≤N≤100),E(1≤E≤N*(N-1)/2),为星系的个数和星系间飞行的路线数。然后E行,每行三个整数i,j和t(1≤i,j≤N,i≠j,-100000≤t≤100000),表示由星系i到星系j飞行的时间为t。由i到j最多只会有一条飞行线路。
OUTPUT
输出文件共T行,每组数据输出一行; 如果可以通过调节速度调节器完成任务,则输出一个非负整数,表示由星系1到星系N的最短时间。 如果不能由星系1到达星系N,则输出-1。
SAMPLEINPUT
1 4 5 1 2 1 1 3 1 2 3 -3 3 1 1 3 4 1
SAMPLEOUTPUT
2
HINT
样例说明 输入样例如图所示,其中节点标号表示相应星系,节点间数字表示所需时间。 如果设置速度控制器的值为0,则有如下路径:1→2→3→1→2→……→3→4,使得投递的时间为负无穷大,显然是不符合要求的,所以应该把速度控制器的值设为1,相当于每个时间值加1,得到的最短路径为1→2→3→4,所需时间为2+(-2)+2=2。
--------------以下是题解-----------------------------
题意简析:题目就是给你一张有向图,你可以对图中所有边的边权加上或者减去一个整数,使得从1~n的最短路在非负的前提下最小。
解题思路:首先用floyd判断是否有解,然后二分答案用SPFAcheck是否有负环并求解,注意解的合法性即可。
附代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<map> 7 #include<set> 8 #include<vector> 9 #include<cmath> 10 #define For(i,a,b) for (int i=a; i<=b; i++) 11 #define Ford(i,a,b) for (int i=a; i>=b; i--) 12 #define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout); 13 #define mem(qaq,num) memset(qaq,num,sizeof(qaq)); 14 #define ll long long 15 #define mod 1000000007 16 #define INF 2000000000 17 using namespace std; 18 struct edge{ 19 int to,next,v; 20 }e[100001]; 21 int head[100001]; 22 int rep[100001]; 23 int dist[100001]; 24 bool mrk[100001]; 25 int go[101][101]; 26 int q[2000001]; 27 int T,n,m,l,r,cnt,ans; 28 inline int in(){ 29 int x=0,f=1; 30 char ch=getchar(); 31 while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar(); 32 while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 33 return x*f; 34 } 35 36 inline void ins(int u,int v,int w) 37 { 38 e[++cnt].to=v; 39 e[cnt].v=w; 40 e[cnt].next=head[u]; 41 head[u]=cnt; 42 } 43 inline int check(int lim) 44 { 45 For(i,1,n)mrk[i]=0; 46 For(i,1,n)dist[i]=INF; 47 For(i,1,n)rep[i]=0; 48 memset(q,0,sizeof(q)); 49 q[1]=1;mrk[1]=1;dist[1]=0;rep[1]=1; 50 int t=0,w=1; 51 while (t<w) 52 { 53 int now=q[++t]; 54 mrk[now]=0; 55 for (int i=head[now];i;i=e[i].next) 56 { 57 if (dist[e[i].to]>dist[now]+e[i].v+lim&&go[e[i].to][n]) 58 { 59 dist[e[i].to]=dist[now]+e[i].v+lim; 60 61 if (!mrk[e[i].to]&&rep[e[i].to]<=n) 62 { 63 mrk[e[i].to]=1; 64 rep[e[i].to]++; 65 if (rep[e[i].to]>n)return -1; 66 q[++w]=e[i].to; 67 } 68 } 69 } 70 } 71 return dist[n]; 72 } 73 inline void doit() 74 { 75 mem(e,0); 76 mem(head,0); 77 mem(go,0); 78 cnt=0; 79 n=in(),m=in(); 80 int mn=INF; 81 int mx=-INF; 82 For(i,1,m) 83 { 84 int x,y,z; 85 x=in(),y=in(),z=in(); 86 ins(x,y,z); 87 mn=min(mn,z); 88 mx=max(mx,z); 89 go[x][y]=1; 90 } 91 For(i,1,n)go[i][i]=1; 92 For(k,1,n) 93 For(i,1,n) 94 For(j,1,n) 95 go[i][j]=go[i][j]|(go[i][k]&go[k][j]); 96 if (!go[1][n]){printf("-1 ");return;} 97 l=-mx;r=-mn; 98 ans=-1; 99 while (l<=r) 100 { 101 int mid=(l+r)>>1,now=check(mid); 102 if (now>=0&&now!=INF){ans=now;r=mid-1;} 103 else l=mid+1; 104 } 105 printf("%d ",ans); 106 } 107 int main() 108 { 109 T=in(); 110 while (T--)doit(); 111 }
本文由Melacau编写,Melacau代表M星向您问好,如果您不是在我的博客http://www.cnblogs.com/Melacau上看到本文,请您向我联系,email:13960948839@163.com.