http://poj.org/problem?id=3662 题意:求一条从1到n 的路径,其中可以选择k条路免费,问该路径中出去k条之后最大的边长度是多少。 比赛的时候想到了一个正确的算法:二分答案+DP判定,但是写挫了一个地方,二分写反了好几遍,最后也没过,回来把二分改了就过了, dp[i][j]表示到达i点经过了j条大于L的路得到的最小的最大值。特判了一下无解和0的情况 还有就是直接dp求解也是可以的,直接把状态表示成dp[i][j]表示到达i点使用了j条免费的路的到的最小的最大值 code1,这个写的好挫,还是两个人各写了一部分 [code lang="cpp"] bool spfa(int L ) { memset(vv,0,sizeof(vv)); memset(dp,-1,sizeof(dp)); while(!q.empty()) q.pop(); bool ffff; ffff = false; node u,tu; u.v = s; u.big = 0 ; vv[s][0] = 1; dp[s][0] = 0; q.push(u); while(!q.empty()) { u = q.front(); q.pop(); if(u.v == n) { if(u.big == k ) { if(dp[n][k] != -1) { ans = min(ans, dp[n][k]); } } if (u.big>=k) ffff = true; vv[u.v][u.big] = 0; continue; } for(int i = head[u.v] ; i!= -1; i = edge[i].next) { int v = edge[i].v; int tmp ; if(edge[i].val <= L ) tmp = max(dp[u.v][u.big], edge[i].val); else tmp = dp[u.v][u.big]; if(edge[i].val > L) { if((tmp < dp[v][u.big + 1] || dp[v][u.big + 1] == -1 )&&(u.big+1<=k)) { dp[v][u.big + 1] = tmp; if(!vv[v][u.big + 1]) { tu.v = v; tu.big = u.big + 1; q.push(tu); vv[v][u.big + 1] = 1; } } } else { if(tmp < dp[v][u.big] || dp[v][u.big] == -1) { dp[v][u.big] = tmp; if(!vv[v][u.big]) { tu.v = v; tu.big = u.big; q.push(tu); vv[v][u.big] = 1; } } } } vv[u.v][u.big] = 0; } return ffff; } bool vis[maxn]; int que[maxn]; int dis[maxn]; bool check() { memset(vis,false,sizeof(vis)); memset(dis,-1,sizeof(dis)); int hh = 0,tail = 1; que[1] = 1; vis[1] = 1; dis[1] = 0; while (hh < tail) { int u = que[++hh]; for (int j= head[u];j!=-1;j=edge[j].next){ int v = edge[j].v; if (dis[u]+1<dis[v] || dis[v] == -1) { dis[v] = dis[u] + 1; if (!vis[v]){ que[++tail] = v; vis[v] = 1; } } } vis[u] = 0; } if (dis[n]!=-1 && dis[n]<=k) return true; return false; } int main() { int u,v,val; while(scanf("%d%d%d",&n,&p,&k)!=EOF) { cnt = 0 ; s = 1; memset(head,-1,sizeof(head)); int mmjh = 0; for(int i = 0 ; i < p ; i ++ ) { scanf("%d%d%d",&u,&v,&val); addedge(u,v,val); mmjh = max(mmjh,val); } if (check()) { printf("0\n"); continue; } int left,right,mid; left = 1 ; right = mmjh; ans = inf; while(left < right ) { mid = (left + right )/2; bool flag; flag = spfa(mid); if(flag == 0 ) { left = mid + 1 ; } else{ right = mid ; } } if (ans == inf) { ans = -1; } printf("%d\n",ans); } return 0; } [/code] code2 [code lang="cpp"] void spfa() { memset(vv,0,sizeof(vv)); for(int i = 0 ; i <= n; i ++ ) { for(int j = 0; j <= k; j ++ ) { dp[i][j] = inf; } } while(!q.empty()) q.pop(); node u,tu; u.v = s; u.big = 0 ; vv[s][0] = 1; dp[s][0] = 0; q.push(u); while(!q.empty()) { u = q.front(); q.pop(); if(u.v == n ) { //printf("%d %d %d\n",u.v,u.big, dp[u.v][u.big]); ans = min(ans , dp[u.v][u.big]); } for(int i = head[u.v] ; i!= -1; i = edge[i].next) { int v = edge[i].v; int tmp ; tmp = max(dp[u.v][u.big] , edge[i].val); if(dp[v][u.big] > tmp ) { dp[v][u.big] = tmp; if(!vv[v][u.big]) { tu.v = v; tu.big = u.big; q.push(tu); vv[v][u.big] = 1; } } if(u.big < k && dp[u.v][u.big] < dp[v][u.big + 1 ] ) { dp[v][u.big + 1] = dp[u.v][u.big]; if(!vv[v][u.big + 1]) { tu.v = v; tu.big = u.big + 1; q.push(tu); vv[v][u.big + 1] = 1; } } } // printf("\n"); vv[u.v][u.big] = 0; } } int main() { int u,v,val; while(scanf("%d%d%d",&n,&p,&k)!=EOF) { cnt = 0 ; s = 1; memset(head,-1,sizeof(head)); for(int i = 0 ; i < p ; i ++ ) { scanf("%d%d%d",&u,&v,&val); addedge(u,v,val); } ans = inf; spfa(); if (ans == inf) { ans = -1; } printf("%d\n",ans); } return 0; } [/code]