时间与空间之旅 解题报告
時間與空間之旅
Time Limit:1000MS? Memory Limit:65536K
Description
公元22XX年,宇宙里最普遍的交通工具是spaceship。Spaceship的出現使得星系之間的聯系變得更為緊密,所以spaceship船長也成了最熱門的職業之一。當然,要成為一名出色的船長,必須通過嚴格的考核,例如下面是最簡單的問題中的一個:
用1~n的整數給n個星系標號,目前你在標號為1的星系,你需要送快遞到標號為n的星系,星系之間由于存在隕石帶,并不是都可以直連的。同時,由于超時空隧道的存在,在某些星系間飛行會出現時間靜止甚至倒流,飛行時間為0或為負數。另外,由星系i到星系j的時間和由星系j到星系i的時間不一定是相同的。
在寄出日期之前收到快遞被認為是不允許的,所以每部spaceship上都有一個速度調節裝置,可以調節飛行的時間。簡單來說其功能就是讓所有兩個星系間的飛行時間(如果可以直達的話)都增加或減少相同的整數值,你的任務就是調整速度調節器,找出一條用最短的時間完成任務的路徑,并且保證這個最短時間的值大于或等于0。
Input
輸入文件tstrip.in 包含多組數據,第一個數為T,表示數據的數量。
對于每一組數據,輸入第一行為兩個正整數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
輸出文件tstrip.out一共T行,每組數據輸出一行:
如果可以通過調節速度調節器完成任務,則輸出一個非負整數,表示由星系1到星系N的最短時間。
如果不能由星系1到達星系N,則輸出-1.
Sample Input
1 4 5 1 2 1 1 3 1 2 3 -3 3 1 1 3 4 1Sample Output
2Hint
輸入樣例如圖所示,其中結點標號表示相應星系,結點間數字表示所需時間。
如果設置速度控制器的值為0,則有如下路徑:1->2->3->1->2->……->3->4,使得投遞的時間為負無窮大,顯然是不符合要求的,所以應該把速度控制器的值設為1,相當于每個時間值加1,得到的最短路徑為1->2->3->4,所需時間為2+(-2)+2=2。
Source
GDOI2007
本題的解法是二分+spfa。
二分需要調整的飛行時間,spfa處理時把每條邊都減去該飛行時間,當1到n的最短時間大于等于0時,符合條件,縮小二分右邊界。
對于不符合條件的情況:
1、1不能到達n,這需要在二分前用floyed傳遞閉包(判斷連通性)預處理判斷;若出現此種情況,直接輸出-1毋需二分;
2、1可以到達n,但最短路上存在負環,這時縮小左邊界;
值得注意的是,有負環也并非一定不成立,只要負環不在最短路上(換句話說,即是負環上的點與n不連通),也是可能成立的;
3、1到n最短時間小于0.
細節處理比較多,比較容易錯的就是負環的處理。
如何判斷負環是否在最短路上?只要當前將拓展的點與n不連通,就不進行拓展,當然如果當前點已經為n,還是需要更新最短時間的。另外,與題目不符,數據中有自環。
(如果你死活過不了,請認真對比下程序,很可能就是某個細節出了問題)
代碼:
#include<cstdio> #include<cstring> using namespace std;int t,n,e,top;int a[101][101];int stack[101];int dist[101];int fre[101];bool f[101][101];bool visited[101]; bool check(int del) //檢查是否滿足條件 {top=1;stack[1]=1;memset(dist,0x7f7f,sizeof(dist));dist[1]=0;memset(visited,false,sizeof(visited));visited[1]=true;memset(fre,0,sizeof(fre));fre[1]=1;while (top>0){int now=stack[top];top--;visited[now]=false;for (int i=1;i<=n;i++)if (a[now][i]<=100000)if (dist[now]+a[now][i]-del<dist[i]&&f[i][n]){dist[i]=dist[now]+a[now][i]-del;if (!visited[i]&&fre[i]<=n) //判負環,由于已經保證當前點與n連通,故只要為負環可直接返回false{visited[i]=true;stack[++top]=i;fre[i]++;if (fre[i]>n) return false;}}}if (dist[n]>=0) return true; else return false; } void floyd() //floyed傳遞閉包判斷連通性 {for (int k=1;k<=n;k++)for (int i=1;i<=n;i++)for (int j=1;j<=n;j++)if (f[i][k]&&f[k][j])f[i][j]=true; } int main() {scanf("%d",&t);while (t!=0){t--;scanf("%d%d",&n,&e);int l=2147483647;int r=-2147483647;memset(a,0x7f7f,sizeof(a));memset(f,false,sizeof(f));for (int i=1;i<=n;i++) f[i][i]=true;for (int i=1;i<=e;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);if (a[u][v]>w) a[u][v]=w;f[u][v]=true;if (w>r) r=w;if (w<l) l=w;}floyd();if (!f[1][n]) //非連通直接輸出-1{printf("-1\n");continue;}int ans;while (l<=r){int mid=(l+r)/2;if (check(mid)) {l=mid+1; ans=dist[n];} else r=mid-1;}printf("%d\n",ans);}return 0; }總結
以上是生活随笔為你收集整理的时间与空间之旅 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 目标检测 YOLOv5网络v6 0版本总
- 下一篇: 基于jsDelivr+GitHub的免费