pku 3662 Telephone Lines 二分+Dijkdtra

http://poj.org/problem?id=3662

开始读这个题目的直接理解错了题意,没想到lengths竟然还有几段的意思;题意求从1到n的每段路径下(除去k各最大的)最长最短问题。

一个无向图有n个点, m条边, 每边有花费val[i], 可以任意指定有k条边免费, 现要求选择若干条边构成顶点1到顶点n的一条路径, 使得路径上边权最大值(不包括免费边)最小. 
 二分答案, 重新建图, Dijkstra

感觉这个讲解比较详细:

我们暂且不考虑最优解的问题, 假设A为一个可行解. 可以知道如果A成立, 则B(B>=A)一定成立. 这说明解具有单调性, 即所有可行解是一个单调序列. 我们模仿二分查找的方法, 对答案进行二分尝试, 对最优解逐步逼近.

对于这道题, 假设A=4这个解成立, 则说明顶点1到N之间必存在某路径, 满足这条路径中长度大于4的边不超过K条(如果超过K条, 4就不是去除K条以外的最大值了, 与题意矛盾).

1. 判断给定的A是否为可行解, 即求从顶点1到顶点N的某条路径上, 长度大于A的边最少有多少条. 如果最少的条数小于等于K, 则A为一个可行解. 
对于求最少的条数, 可以在原图的基础上构造一个新图, 改变边权. 如果一条边原来的权值大于A, 则在新图中将其权值设为1;如果一条边原来的权值小于等于A, 则在新图中将其权值设为0. 
然后求出从顶点1到N的最短路径长度D, D即为从顶点1到顶点N的某条路径上, 长度大于A的边最少有多少条. 如果D<=K, 则A为可行解.

View Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define maxn 1007
#define inf 99999999
using namespace std;

int map[maxn][maxn];
struct node
{
    int x,y;
    int val;
}p[maxn*10];

int n,m,k;
int dis[maxn];
bool vt[maxn];

int cmp(node a,node b)
{
    return a.val < b.val;
}
void init()
{
    int i,j;
    for (i = 0; i <= n; ++i)
    {
        for (j = 0; j <= n; ++j)
        {
            if (i == j) map[i][j] = 0;
            else map[i][j]  = inf;
        }
    }
}

void Dijkstra()
{
    int i,j,min;
    for (i = 1; i <= n; ++i)
    {
        vt[i] = false;
        dis[i] = map[1][i];
    }
    vt[1] = true;
    for (int ki = 1; ki < n; ++ki)
    {
        j = 1; min = inf;
        for (i = 2; i <= n; ++i)
        {
            if (!vt[i] && dis[i] < min)
            {
                j = i; min = dis[i];
            }
        }
        if (min == inf) break;
        vt[j] = true;
        for (i = 2; i <= n; ++i)
        {
            if (!vt[i] && dis[i] > map[i][j] + dis[j] && map[i][j] != inf)
            {
                dis[i] = map[i][j] + dis[j];
            }
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int i;
    int x,y,z;
    scanf("%d%d%d",&n,&m,&k);
    init();
    for (i = 1; i <= m; ++i)
    {
        scanf("%d%d%d",&x,&y,&z);
        map[x][y] = map[y][x] = 1;
        p[i].x = x; p[i].y = y;
        p[i].val = z;
    }
//按边的权值排序
    sort(p + 1, p + 1 + m, cmp);
    int l = 0, r = m - 1;
    int ms = 0,ans = -1;
    p[0].val = 0;//注意这里0的处理
    while (l <= r)
    {
        int mid = (l + r)/2;
//ms的左边都是0,右边都是1
        if (ms <= mid)
        {
            for (i = ms; i <= mid; ++i)
            {
                map[p[i].x][p[i].y] = map[p[i].y][p[i].x] = 0;
            }
        }
        else
        {
            for (i = mid + 1; i <= ms; ++i)
            {
                map[p[i].x][p[i].y] = map[p[i].y][p[i].x] = 1;
            }
        }
        ms = mid;
        Dijkstra();
        if (dis[n] > k) l = mid + 1;
        else
        {
            ans = mid; r = mid - 1;
        }
    }
    //printf("%d\n",ans);
    if (ans == - 1) printf("-1\n");
    else printf("%d\n",p[ans].val);
    return 0;
}

 

 

posted @ 2012-05-06 15:40  E_star  阅读(288)  评论(0编辑  收藏  举报