Calabash(葫芦娃)
这题考试的时候并没有想出来……还是自己太弱了。
当时的想法是如何找到一条最短而且经过点最多的路,之后就一直卡在这上面出不来了……
但后来发现并不需要这样,因为我们要求的是……路径长和经过点数的比值,所以我们可以选择在原图中跑spfa或者dij,每次走到一个新的点,就把当前点数设置为转移过来的那个地方的点数+1,之后直接判断如果当前的比值更小就更新即可。
这样是可以保证正确性的,因为它肯定会取到所有的情况,即使当前的情况并不是很优秀,它将来一定会在某个位置被更优秀的情况所取代。
然后就可以了……这题不需要瞎考虑怎么记录路径上的点数……自己就是死在这里……
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<queue> #include<set> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 100005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct edge { int next,to,from; double v; }e[M]; int n,m,head[1005],x,y,ecnt; double z,ans,dis[1005],dep[1005]; set<pair<double,int> > q; set<pair<double,int> > :: iterator it; void add(int x,int y,int z) { e[++ecnt].to = y; e[ecnt].v = z; e[ecnt].from = x; e[ecnt].next = head[x]; head[x] = ecnt; } void dijk(int s) { q.insert(make_pair(dis[s],s)); dis[s] = 0,dep[s] = 1; while(!q.empty()) { pair<double,int> k = *(q.begin()); q.erase(q.begin()); int g = k.second; for(int i = head[g];i;i = e[i].next) { double d1 = dis[g] + e[i].v; double d2 = dep[g] + 1; if(d1 / d2 < dis[e[i].to] / dep[e[i].to] || (dis[e[i].to] == 0 && dep[e[i].to] == 0)) { dis[e[i].to] = d1,dep[e[i].to] = d2;//在这里判断是否符合并且更新 q.insert(make_pair(d1/d2,e[i].to)); } } } } int main() { // freopen("calabash.in","r",stdin); // freopen("calabash.out","w",stdout); n = read(),m = read(); rep(i,1,n) dis[i] = 999999999; rep(i,1,m) x = read(),y = read(),scanf("%lf",&z),add(x,y,z); dijk(1); printf("%.3lf\n",dis[n] / dep[n]); return 0; }
当你意识到,每个上一秒都成为永恒。