在看题之前,我已经预先知道这是道ufs。所以做它的目的本来就是练ufs。但。。由于对ufs掌握不够纯熟,想了很久也没有想出正解。
STEP 1:刚看到题的时候就感觉很像前几天做的最优贸易,可以用SPFA写一个DP,但写完了不对,完全不存在最优子结构,连样例都过不了。。。
---------------------------------------------------------------------------------------------------------------------------
STEP 2: 然后我突然发现m<=5*10^3,是个相当稀疏的图。如果用类似次短路的做法,从初始图开始,依次删去剩余图中权值最大的边,并用SPFA求S->T并过该边的最小权值最大的路径,这样的话是2m遍SPFA的算法,时间复杂度为O(ke(n+e))≈4*5*10^3(5*10^2+5*10^3)≈1.001*10^8,如果数据水的话。。队列的SPFA应该是就可以卡过的。。可如果数据很强就要用堆优化了。。我好像还不会。。
---------------------------------------------------------------------------------------------------------------------------
STEP 3:然后我不知道怎么回事突然觉得DFS说不定也可以。。然后就脑抽写了个DFS先,我去竟然还真过了4个点。。拿了80分。。在DFS的过程中。。我发现原来这题时限2s,那朴素SPFA就也一定一点问题都没有了。
---------------------------------------------------------------------------------------------------------------------------
STEP 4: 于是开始动手写SPFA,但是在写的过程中遇到了各种各样的让我头大的问题。主要是这道题的题面应该说是很坑爹的,删掉权值最大的边的话,我应该是求的“最小权值”“最大”的路径,于是一不小心就晕掉了。以后写题这种地方一定要小心小心再小心,保持头脑清醒!
---------------------------------------------------------------------------------------------------------------------------
STEP 5:虽然A掉了这道题,但ufs的阴影始终挥之不去, 于是看了题解。。。原来是用了一种类似Kruskal的方法,从最大边开始往下加边,直到S与T连通;然后从次大边、次次大边……这种方法。。应该说是要高级一些的,首先是O(ke^2)比我快,其次这也帮助我认识和熟悉了Kruskal算法。
附上代码:- -好丑啊。。
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define hd short
using namespace std;
bool v[501];
hd p[501],s[10001],n[10001];
void dfs(hd x){
hd j=p[x];
while(j){
if(!v[s[j]])
v[s[j]]=1,dfs(s[j]);
j=n[j];
}
}
int gcd(int a,int b){
int c=a%b;
return c?gcd(b,c):b;
}
int main(){
int r[10001],tmp,mp,ms,m[501],m0,m1,g;
const int MAXN=0x7fffffff;
hd N,M,i=-1,tot=0,totm,pred[10001],j,q[501],h,t,S,T;
double ans=pow(10,10),tmpiu;
bool vst[501];
scanf("%hd%hd",&N,&M);
totm=M;
memset(p,0,2*++N);
while(++i<M){
++tot;
scanf("%hd%hd%u",pred+tot,s+tot,r+tot);
n[tot]=p[pred[tot]],p[pred[tot]]=tot;
n[++totm]=p[s[tot]],p[s[tot]]=totm,s[totm]=pred[tot],r[totm]=r[tot];
}
scanf("%hd%hd",&S,&T);
dfs(T);
if(!v[S]){
printf("IMPOSSIBLE");
return 0;
}
++M;
for(i=0;++i<M;)
if(v[pred[i]]){
memset(m,-1,4*N),memset(vst,0,N);
q[h=t=0]=S;
m[S]=MAXN;
do{
h%=N;
j=p[q[h]];
vst[q[h]]=0;
while(j){
if(r[j]<=r[i]){
tmp=min(m[q[h]],r[j]);
if(tmp>m[s[j]]){
m[s[j]]=tmp;
if(!vst[s[j]])
vst[s[j]]=1,q[t=(t+1)%N]=s[j];
}
}
j=n[j];
}
}while(h++!=t);
mp=m[pred[i]],ms=m[s[i]];
q[h=t=0]=T;
memset(m,-1,4*N),memset(vst,0,N);
m[T]=MAXN;
do{
h%=N;
j=p[q[h]];
vst[q[h]]=0;
while(j){
if(r[j]<=r[i]){
tmp=min(m[q[h]],r[j]);
if(tmp>m[s[j]]){
m[s[j]]=tmp;
if(!vst[s[j]])
vst[s[j]]=1,q[t=(t+1)%N]=s[j];
}
}
j=n[j];
}
}while(h++!=t);
tmp=max(min(mp,m[s[i]]),min(ms,m[pred[i]]));
if(tmp<0)continue;
if(tmp==MAXN){
printf("1");
return 0;
}
tmpiu=(double(r[i]))/tmp;
if(tmpiu<ans){
ans=tmpiu;
m0=r[i];
m1=tmp;
}
}
g=gcd(m0,m1);
if(g!=m1)printf("%u/%u",m0/g,m1/g);
else printf("%u",m0/g);
}